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"); 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.previousCouponRate(), floatingRateBond.previousCouponRate()); Console.WriteLine("Next coupon".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}", "N/A", fixedRateBond.nextCouponRate(), floatingRateBond.nextCouponRate()); 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 testBond() { /* when deeply out-of-the-money, the value of the convertible bond * should equal that of the underlying plain-vanilla bond. */ // Testing out-of-the-money convertible bonds against vanilla bonds CommonVars vars = new CommonVars(); vars.conversionRatio = 1.0e-16; Exercise euExercise = new EuropeanExercise(vars.maturityDate); Exercise amExercise = new AmericanExercise(vars.issueDate, vars.maturityDate); int timeSteps = 1001; IPricingEngine engine = new BinomialConvertibleEngine <CoxRossRubinstein>(vars.process, timeSteps); Handle <YieldTermStructure> discountCurve = new Handle <YieldTermStructure>(new ForwardSpreadedTermStructure(vars.riskFreeRate, vars.creditSpread)); // zero-coupon Schedule schedule = new MakeSchedule().from(vars.issueDate) .to(vars.maturityDate) .withFrequency(Frequency.Once) .withCalendar(vars.calendar) .backwards().value(); ConvertibleZeroCouponBond euZero = new ConvertibleZeroCouponBond(euExercise, vars.conversionRatio, vars.no_dividends, vars.no_callability, vars.creditSpread, vars.issueDate, vars.settlementDays, vars.dayCounter, schedule, vars.redemption); euZero.setPricingEngine(engine); ConvertibleZeroCouponBond amZero = new ConvertibleZeroCouponBond(amExercise, vars.conversionRatio, vars.no_dividends, vars.no_callability, vars.creditSpread, vars.issueDate, vars.settlementDays, vars.dayCounter, schedule, vars.redemption); amZero.setPricingEngine(engine); ZeroCouponBond zero = new ZeroCouponBond(vars.settlementDays, vars.calendar, 100.0, vars.maturityDate, BusinessDayConvention.Following, vars.redemption, vars.issueDate); IPricingEngine bondEngine = new DiscountingBondEngine(discountCurve); zero.setPricingEngine(bondEngine); double tolerance = 1.0e-2 * (vars.faceAmount / 100.0); double error = Math.Abs(euZero.NPV() - zero.settlementValue()); if (error > tolerance) { QAssert.Fail("failed to reproduce zero-coupon bond price:" + "\n calculated: " + euZero.NPV() + "\n expected: " + zero.settlementValue() + "\n error: " + error); } error = Math.Abs(amZero.NPV() - zero.settlementValue()); if (error > tolerance) { QAssert.Fail("failed to reproduce zero-coupon bond price:" + "\n calculated: " + amZero.NPV() + "\n expected: " + zero.settlementValue() + "\n error: " + error); } // coupon List <double> coupons = new InitializedList <double>(1, 0.05); schedule = new MakeSchedule().from(vars.issueDate) .to(vars.maturityDate) .withFrequency(vars.frequency) .withCalendar(vars.calendar) .backwards().value(); ConvertibleFixedCouponBond euFixed = new ConvertibleFixedCouponBond(euExercise, vars.conversionRatio, vars.no_dividends, vars.no_callability, vars.creditSpread, vars.issueDate, vars.settlementDays, coupons, vars.dayCounter, schedule, vars.redemption); euFixed.setPricingEngine(engine); ConvertibleFixedCouponBond amFixed = new ConvertibleFixedCouponBond(amExercise, vars.conversionRatio, vars.no_dividends, vars.no_callability, vars.creditSpread, vars.issueDate, vars.settlementDays, coupons, vars.dayCounter, schedule, vars.redemption); amFixed.setPricingEngine(engine); FixedRateBond fixedBond = new FixedRateBond(vars.settlementDays, vars.faceAmount, schedule, coupons, vars.dayCounter, BusinessDayConvention.Following, vars.redemption, vars.issueDate); fixedBond.setPricingEngine(bondEngine); tolerance = 2.0e-2 * (vars.faceAmount / 100.0); error = Math.Abs(euFixed.NPV() - fixedBond.settlementValue()); if (error > tolerance) { QAssert.Fail("failed to reproduce fixed-coupon bond price:" + "\n calculated: " + euFixed.NPV() + "\n expected: " + fixedBond.settlementValue() + "\n error: " + error); } error = Math.Abs(amFixed.NPV() - fixedBond.settlementValue()); if (error > tolerance) { QAssert.Fail("failed to reproduce fixed-coupon bond price:" + "\n calculated: " + amFixed.NPV() + "\n expected: " + fixedBond.settlementValue() + "\n error: " + error); } // floating-rate IborIndex index = new Euribor1Y(discountCurve); int fixingDays = 2; List <double> gearings = new InitializedList <double>(1, 1.0); List <double> spreads = new List <double>(); ConvertibleFloatingRateBond euFloating = new ConvertibleFloatingRateBond(euExercise, vars.conversionRatio, vars.no_dividends, vars.no_callability, vars.creditSpread, vars.issueDate, vars.settlementDays, index, fixingDays, spreads, vars.dayCounter, schedule, vars.redemption); euFloating.setPricingEngine(engine); ConvertibleFloatingRateBond amFloating = new ConvertibleFloatingRateBond(amExercise, vars.conversionRatio, vars.no_dividends, vars.no_callability, vars.creditSpread, vars.issueDate, vars.settlementDays, index, fixingDays, spreads, vars.dayCounter, schedule, vars.redemption); amFloating.setPricingEngine(engine); IborCouponPricer pricer = new BlackIborCouponPricer(new Handle <OptionletVolatilityStructure>()); Schedule floatSchedule = new Schedule(vars.issueDate, vars.maturityDate, new Period(vars.frequency), vars.calendar, BusinessDayConvention.Following, BusinessDayConvention.Following, DateGeneration.Rule.Backward, false); FloatingRateBond floating = new FloatingRateBond(vars.settlementDays, vars.faceAmount, floatSchedule, index, vars.dayCounter, BusinessDayConvention.Following, fixingDays, gearings, spreads, new List <double?>(), new List <double?>(), false, vars.redemption, vars.issueDate); floating.setPricingEngine(bondEngine); Utils.setCouponPricer(floating.cashflows(), pricer); tolerance = 2.0e-2 * (vars.faceAmount / 100.0); error = Math.Abs(euFloating.NPV() - floating.settlementValue()); if (error > tolerance) { QAssert.Fail("failed to reproduce floating-rate bond price:" + "\n calculated: " + euFloating.NPV() + "\n expected: " + floating.settlementValue() + "\n error: " + error); } error = Math.Abs(amFloating.NPV() - floating.settlementValue()); if (error > tolerance) { QAssert.Fail("failed to reproduce floating-rate bond price:" + "\n calculated: " + amFloating.NPV() + "\n expected: " + floating.settlementValue() + "\n error: " + error); } }
static void Main(string[] args) { try { var timer = new System.Diagnostics.Stopwatch(); timer.Start(); #region MARKET DATA var calendar = new TARGET(); var settlementDate = new Date(18, Month.September, 2008); // must be a business day settlementDate = calendar.adjust(settlementDate); int fixingDays = 3; uint settlementDays = 3; var todaysDate = calendar.advance(settlementDate, -fixingDays, TimeUnit.Days); // nothing to do with Date::todaysDate Settings.instance().setEvaluationDate(todaysDate); Console.WriteLine("Today: {0} {1} {2} {3}", todaysDate.weekday(), todaysDate.dayOfMonth(), todaysDate.month(), todaysDate.year()); Console.WriteLine("Settlement date: {0} {1} {2} {3}", settlementDate.weekday(), settlementDate.dayOfMonth(), settlementDate.month(), settlementDate.year()); // Building of the bonds discounting yield curve #endregion #region 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; var zc3mRate = new SimpleQuote(zc3mQuote); var zc6mRate = new SimpleQuote(zc6mQuote); var zc1yRate = new SimpleQuote(zc1yQuote); var zcBondsDayCounter = new Actual365Fixed(); var zc3m = new DepositRateHelper(new QuoteHandle(zc3mRate), new Period(3, TimeUnit.Months), (uint)fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); var zc6m = new DepositRateHelper(new QuoteHandle(zc6mRate), new Period(6, TimeUnit.Months), (uint)fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); var zc1y = new DepositRateHelper(new QuoteHandle(zc1yRate), new Period(1, TimeUnit.Years), (uint)fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); // setup bonds double redemption = 100.0; const uint numberOfBonds = 5; var issueDates = new Date[] { 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) }; var maturities = new Date[] { 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) }; var couponRates = new double[] { 0.02375, 0.04625, 0.03125, 0.04000, 0.04500 }; var marketQuotes = new double[] { 100.390625, 106.21875, 100.59375, 101.6875, 102.140625 }; var quote = new QuoteVector((int)numberOfBonds); for (uint i = 0; i < numberOfBonds; i++) { var cp = new SimpleQuote(marketQuotes[i]); quote.Add(cp); } var quoteHandle = new RelinkableQuoteHandleVector((int)numberOfBonds); for (int i = 0; i < (int)numberOfBonds; i++) { quoteHandle.Add(new RelinkableQuoteHandle()); quoteHandle[i].linkTo(quote[i]); } // Definition of the rate helpers var bondsHelpers = new RateHelperVector((int)numberOfBonds); for (int i = 0; i < (int)numberOfBonds; i++) { var schedule = new Schedule(issueDates[i], maturities[i], new Period(Frequency.Semiannual), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); var bondHelper = new FixedRateBondHelper(quoteHandle[i], settlementDays, 100.0, schedule, new DoubleVector(1) { couponRates[i] }, new ActualActual(ActualActual.Convention.Bond), BusinessDayConvention.Unadjusted, redemption, issueDates[i]); bondsHelpers.Add(bondHelper); } #endregion #region CURVE BUILDING // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 var termStructureDayCounter = new ActualActual(ActualActual.Convention.ISDA); //double tolerance = 1.0e-15; // A depo-bond curve var bondInstruments = new RateHelperVector(); // 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[3]); } var bondDiscountingTermStructure = new PiecewiseFlatForward(settlementDate, bondInstruments, termStructureDayCounter); // 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; #endregion #region 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 var d1wRate = new SimpleQuote(d1wQuote); var d1mRate = new SimpleQuote(d1mQuote); var d3mRate = new SimpleQuote(d3mQuote); var d6mRate = new SimpleQuote(d6mQuote); var d9mRate = new SimpleQuote(d9mQuote); var d1yRate = new SimpleQuote(d1yQuote); // swaps var s2yRate = new SimpleQuote(s2yQuote); var s3yRate = new SimpleQuote(s3yQuote); var s5yRate = new SimpleQuote(s5yQuote); var s10yRate = new SimpleQuote(s10yQuote); var s15yRate = new SimpleQuote(s15yQuote); #endregion #region 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 var depositDayCounter = new Actual360(); var d1w = new DepositRateHelper(new QuoteHandle(d1wRate), new Period(1, TimeUnit.Weeks), (uint)fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); var d1m = new DepositRateHelper(new QuoteHandle(d1mRate), new Period(1, TimeUnit.Months), (uint)fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); var d3m = new DepositRateHelper(new QuoteHandle(d3mRate), new Period(3, TimeUnit.Months), (uint)fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); var d6m = new DepositRateHelper(new QuoteHandle(d6mRate), new Period(6, TimeUnit.Months), (uint)fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); var d9m = new DepositRateHelper(new QuoteHandle(d9mRate), new Period(9, TimeUnit.Months), (uint)fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); var d1y = new DepositRateHelper(new QuoteHandle(d1yRate), new Period(1, TimeUnit.Years), (uint)fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); // setup swaps var swFixedLegFrequency = Frequency.Annual; var swFixedLegConvention = BusinessDayConvention.Unadjusted; var swFixedLegDayCounter = new Thirty360(Thirty360.Convention.European); var swFloatingLegIndex = new Euribor6M(); var forwardStart = new Period(1, TimeUnit.Days); var s2y = new SwapRateHelper(new QuoteHandle(s2yRate), new Period(2, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new QuoteHandle(), forwardStart); var s3y = new SwapRateHelper(new QuoteHandle(s3yRate), new Period(3, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new QuoteHandle(), forwardStart); var s5y = new SwapRateHelper(new QuoteHandle(s5yRate), new Period(5, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new QuoteHandle(), forwardStart); var s10y = new SwapRateHelper(new QuoteHandle(s10yRate), new Period(10, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new QuoteHandle(), forwardStart); var s15y = new SwapRateHelper(new QuoteHandle(s15yRate), new Period(15, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new QuoteHandle(), forwardStart); #endregion #region CURVE BUILDING // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 // A depo-swap curve var depoSwapInstruments = new RateHelperVector(); 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); var depoSwapTermStructure = new PiecewiseFlatForward(settlementDate, depoSwapInstruments, termStructureDayCounter); // Term structures that will be used for pricing: // the one used for discounting cash flows var discountingTermStructure = new RelinkableYieldTermStructureHandle(); // the one used for forward rate forecasting //var forecastingTermStructure = new RelinkableYieldTermStructureHandle(); #endregion #region BONDS TO BE PRICED // Common data double faceAmount = 100; // Pricing engine var bondEngine = new DiscountingBondEngine(new YieldTermStructureHandle(bondDiscountingTermStructure)); // Zero coupon bond var 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 var 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); var fixedRateBond = new FixedRateBond((int)settlementDays, faceAmount, fixedBondSchedule, new DoubleVector(1) { 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... var liborTermStructure = new RelinkableYieldTermStructureHandle(); var libor3m = new USDLibor(new Period(3, TimeUnit.Months), liborTermStructure); libor3m.addFixing(new Date(17, Month.July, 2008), 0.0278625); var 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); var floatingRateBond = new FloatingRateBond(settlementDays, faceAmount, floatingBondSchedule, libor3m, new Actual360(), BusinessDayConvention.ModifiedFollowing, 2, // Gearings new DoubleVector(1) { 1.0 }, // Spreads new DoubleVector(1) { 0.001 }, // Caps new DoubleVector(), // Floors new DoubleVector(), // Fixing in arrears true, 100.0, new Date(21, Month.October, 2005)); floatingRateBond.setPricingEngine(bondEngine); // Coupon pricers var pricer = new BlackIborCouponPricer(); // optionLet volatilities double volatility = 0.0; var vol = new OptionletVolatilityStructureHandle(new ConstantOptionletVolatility(settlementDays, calendar, BusinessDayConvention.ModifiedFollowing, volatility, new Actual365Fixed())); pricer.setCapletVolatility(vol); NQuantLibc.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); #endregion #region BOND PRICING Console.WriteLine(); // write column headings int[] widths = new int[] { 0, 28, 38, 48 }; Console.CursorLeft = widths[0]; Console.Write(" "); Console.CursorLeft = widths[1]; Console.Write("ZC"); Console.CursorLeft = widths[2]; Console.Write("Fixed"); Console.CursorLeft = widths[3]; Console.WriteLine("Floating"); //string separator = " | "; int width = widths[3]; string rule = new string('-', width); string dblrule = new string('=', width); string tab = new string(' ', 8); Console.WriteLine(rule); Console.CursorLeft = widths[0]; Console.Write("Net present value"); Console.CursorLeft = widths[1]; Console.Write(zeroCouponBond.NPV().ToString("000.00")); Console.CursorLeft = widths[2]; Console.Write(fixedRateBond.NPV().ToString("000.00")); Console.CursorLeft = widths[3]; Console.WriteLine(floatingRateBond.NPV().ToString("000.00")); Console.CursorLeft = widths[0]; Console.Write("Clean price"); Console.CursorLeft = widths[1]; Console.Write(zeroCouponBond.cleanPrice().ToString("000.00")); Console.CursorLeft = widths[2]; Console.Write(fixedRateBond.cleanPrice().ToString("000.00")); Console.CursorLeft = widths[3]; Console.WriteLine(floatingRateBond.cleanPrice().ToString("000.00")); Console.CursorLeft = widths[0]; Console.Write("Dirty price"); Console.CursorLeft = widths[1]; Console.Write(zeroCouponBond.dirtyPrice().ToString("000.00")); Console.CursorLeft = widths[2]; Console.Write(fixedRateBond.dirtyPrice().ToString("000.00")); Console.CursorLeft = widths[3]; Console.WriteLine(floatingRateBond.dirtyPrice().ToString("000.00")); Console.CursorLeft = widths[0]; Console.Write("Accrued coupon"); Console.CursorLeft = widths[1]; Console.Write(zeroCouponBond.accruedAmount().ToString("000.00")); Console.CursorLeft = widths[2]; Console.Write(fixedRateBond.accruedAmount().ToString("000.00")); Console.CursorLeft = widths[3]; Console.WriteLine(floatingRateBond.accruedAmount().ToString("000.00")); Console.CursorLeft = widths[0]; Console.Write("Previous coupon"); Console.CursorLeft = widths[1]; Console.Write("N/A"); Console.CursorLeft = widths[2]; Console.Write(fixedRateBond.previousCouponRate().ToString("000.00")); Console.CursorLeft = widths[3]; Console.WriteLine(floatingRateBond.previousCouponRate().ToString("000.00")); Console.CursorLeft = widths[0]; Console.Write("Next coupon"); Console.CursorLeft = widths[1]; Console.Write("N/A"); Console.CursorLeft = widths[2]; Console.Write(fixedRateBond.nextCouponRate().ToString("000.00")); Console.CursorLeft = widths[3]; Console.WriteLine(floatingRateBond.nextCouponRate().ToString("000.00")); Console.CursorLeft = widths[0]; Console.Write("Yield"); Console.CursorLeft = widths[1]; Console.Write(zeroCouponBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual).ToString("000.00")); Console.CursorLeft = widths[2]; Console.Write(fixedRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual).ToString("000.00")); Console.CursorLeft = widths[3]; Console.WriteLine(floatingRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual).ToString("000.00")); double yield = fixedRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual); Console.CursorLeft = widths[2]; Console.Write(BondFunctions.duration(fixedRateBond, new InterestRate(yield, fixedRateBond.dayCounter(), Compounding.Compounded, Frequency.Annual), Duration.Type.Modified)); Console.WriteLine(); // Other computations Console.WriteLine("Sample indirect computations (for the floating rate bond): "); Console.WriteLine(rule); Console.WriteLine("Yield to Clean Price: {0}", floatingRateBond.cleanPrice(floatingRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual), new Actual360(), Compounding.Compounded, Frequency.Annual, settlementDate).ToString("000.00")); Console.WriteLine("Clean Price to Yield: {0}", floatingRateBond.yield(floatingRateBond.cleanPrice(), new Actual360(), Compounding.Compounded, Frequency.Annual, settlementDate).ToString("000.00")); /* "Yield to Price" * "Price to Yield" */ double milliseconds = timer.ElapsedMilliseconds; Console.WriteLine(); Console.WriteLine("Run completed in " + milliseconds + "ms"); #endregion } catch (Exception e) { Console.WriteLine(e.Message); } finally { Console.Read(); } }
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)); } }
public void testRiskFreeAgainstFloatingRateBond() { // Testing floating-rate cat bond against risk-free floating-rate bond CommonVars vars = new CommonVars(); Date today = new Date(22, Month.November, 2004); Settings.setEvaluationDate(today); int settlementDays = 1; Handle <YieldTermStructure> riskFreeRate = new Handle <YieldTermStructure>(Utilities.flatRate(today, 0.025, new Actual360())); Handle <YieldTermStructure> discountCurve = new Handle <YieldTermStructure>(Utilities.flatRate(today, 0.03, new Actual360())); IborIndex index = new USDLibor(new Period(6, TimeUnit.Months), riskFreeRate); int fixingDays = 1; double tolerance = 1.0e-6; IborCouponPricer pricer = new BlackIborCouponPricer(new Handle <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); CatRisk noCatRisk = new EventSet(new List <KeyValuePair <Date, double> >(), new Date(1, Month.Jan, 2000), new Date(31, Month.Dec, 2010)); EventPaymentOffset paymentOffset = new NoOffset(); NotionalRisk notionalRisk = new DigitalNotionalRisk(paymentOffset, 100); 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)); FloatingCatBond catBond1 = new FloatingCatBond(settlementDays, vars.faceAmount, sch, index, new ActualActual(ActualActual.Convention.ISMA), notionalRisk, 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); IPricingEngine catBondEngine = new MonteCarloCatBondEngine(noCatRisk, riskFreeRate); catBond1.setPricingEngine(catBondEngine); Utils.setCouponPricer(catBond1.cashflows(), pricer); #if QL_USE_INDEXED_COUPON double cachedPrice1 = 99.874645; #else double cachedPrice1 = 99.874646; #endif double price = bond1.cleanPrice(); double catPrice = catBond1.cleanPrice(); if (Math.Abs(price - cachedPrice1) > tolerance || Math.Abs(catPrice - price) > tolerance) { QAssert.Fail("failed to reproduce floating rate bond price:\n" + " floating bond: " + price + "\n" + " catBond bond: " + catPrice + "\n" + " expected: " + cachedPrice1 + "\n" + " error: " + (catPrice - price)); } // 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)); FloatingCatBond catBond2 = new FloatingCatBond(settlementDays, vars.faceAmount, sch, index, new ActualActual(ActualActual.Convention.ISMA), notionalRisk, 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); IPricingEngine catBondEngine2 = new MonteCarloCatBondEngine(noCatRisk, discountCurve); catBond2.setPricingEngine(catBondEngine2); Utils.setCouponPricer(catBond2.cashflows(), pricer); #if QL_USE_INDEXED_COUPON double cachedPrice2 = 97.955904; #else double cachedPrice2 = 97.955904; #endif price = bond2.cleanPrice(); catPrice = catBond2.cleanPrice(); if (Math.Abs(price - cachedPrice2) > tolerance || Math.Abs(catPrice - price) > tolerance) { QAssert.Fail("failed to reproduce floating rate bond price:\n" + " floating bond: " + price + "\n" + " catBond bond: " + catPrice + "\n" + " expected: " + cachedPrice2 + "\n" + " error: " + (catPrice - price)); } // varying spread List <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)); FloatingCatBond catBond3 = new FloatingCatBond(settlementDays, vars.faceAmount, sch, index, new ActualActual(ActualActual.Convention.ISMA), notionalRisk, 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); catBond3.setPricingEngine(catBondEngine2); Utils.setCouponPricer(catBond3.cashflows(), pricer); #if QL_USE_INDEXED_COUPON double cachedPrice3 = 98.495458; #else double cachedPrice3 = 98.495459; #endif price = bond3.cleanPrice(); catPrice = catBond3.cleanPrice(); if (Math.Abs(price - cachedPrice3) > tolerance || Math.Abs(catPrice - price) > tolerance) { QAssert.Fail("failed to reproduce floating rate bond price:\n" + " floating bond: " + price + "\n" + " catBond bond: " + catPrice + "\n" + " expected: " + cachedPrice2 + "\n" + " error: " + (catPrice - price)); } }
static void Main(string[] args) { double nominal = 575000000; Date _marketDate; Date _settlementDate; Dictionary <string, double> _depositRates; Dictionary <string, double> _swapRates; List <RateHelper> _rateHelpers; Calendar _calendar = new TARGET(); int _fixingDays = 2; _marketDate = new Date(new DateTime(2015, 12, 17)); Settings.setEvaluationDate(_marketDate); _depositRates = new Dictionary <string, double>(); _depositRates.Add("1M", 0.0045); _depositRates.Add("3M", 0.0070); _depositRates.Add("6M", 0.0090); _swapRates = new Dictionary <string, double>(); _swapRates.Add("1Y", 0.0080); _swapRates.Add("2Y", 0.0109); _swapRates.Add("3Y", 0.0134); _swapRates.Add("4Y", 0.0153); _swapRates.Add("5Y", 0.0169); _swapRates.Add("7Y", 0.0193); _swapRates.Add("10Y", 0.0218); _swapRates.Add("30Y", 0.0262); _rateHelpers = new List <RateHelper>(); foreach (var v in _depositRates) { SimpleQuote sq = new SimpleQuote(v.Value); _rateHelpers.Add(new DepositRateHelper(new Handle <Quote>(sq), new Period(v.Key), _fixingDays, _calendar, BusinessDayConvention.ModifiedFollowing, true, new Actual360())); } foreach (var v in _swapRates) { SimpleQuote sq = new SimpleQuote(v.Value); _rateHelpers.Add(new SwapRateHelper(new Handle <Quote>(sq), new Period(v.Key), _calendar, Frequency.Semiannual, BusinessDayConvention.Unadjusted, new Thirty360(Thirty360.Thirty360Convention.USA), new Euribor3M())); } _marketDate = _calendar.adjust(_marketDate); _settlementDate = _calendar.advance(_marketDate, _fixingDays, TimeUnit.Days); YieldTermStructure yieldTermStructure = new PiecewiseYieldCurve <Discount, LogLinear>( _settlementDate, _rateHelpers, new ActualActual(ActualActual.Convention.ISDA)); RelinkableHandle <YieldTermStructure> yieldTermStructureHandle = new RelinkableHandle <YieldTermStructure>(); Frequency fixedLegFrequency = Frequency.Semiannual; BusinessDayConvention fixedLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter fixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.USA); double fixedRate = 0.0144; Frequency floatLegFrequency = Frequency.Quarterly; BusinessDayConvention floatLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter floatLegDayCounter = new Actual360(); IborIndex iborIndex = new Euribor3M(yieldTermStructureHandle); iborIndex.addFixing(new Date(18, Month.Aug, 2015), 0.0033285); iborIndex.addFixing(new Date(18, Month.Nov, 2015), 0.0036960); double floatSpread = 0.0; VanillaSwap.Type swapType = VanillaSwap.Type.Receiver; Date maturity = new Date(20, Month.Nov, 2018); Date effective = new Date(20, Month.Nov, 2013); Schedule fixedSchedule = new Schedule(effective, maturity, new Period(fixedLegFrequency), _calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false); Schedule floatSchedule = new Schedule(effective, maturity, new Period(floatLegFrequency), _calendar, floatLegConvention, floatLegConvention, DateGeneration.Rule.Forward, false); VanillaSwap vanillaSwap = new VanillaSwap(swapType, nominal, fixedSchedule, fixedRate, fixedLegDayCounter, floatSchedule, iborIndex, floatSpread, floatLegDayCounter); InterestRate interestRate = new InterestRate(fixedRate, fixedLegDayCounter, Compounding.Simple, fixedLegFrequency); List <InterestRate> coupons = new List <InterestRate>(); for (int i = 0; i < fixedSchedule.Count; i++) { coupons.Add(interestRate); } FixedRateBond fixedBond = new FixedRateBond(_fixingDays, nominal, fixedSchedule, coupons, BusinessDayConvention.ModifiedFollowing); FloatingRateBond floatBond = new FloatingRateBond(_fixingDays, nominal, floatSchedule, iborIndex, floatLegDayCounter); IPricingEngine bondPricingEngine = new DiscountingBondEngine(yieldTermStructureHandle); fixedBond.setPricingEngine(bondPricingEngine); floatBond.setPricingEngine(bondPricingEngine); IPricingEngine swapPricingEngine = new DiscountingSwapEngine(yieldTermStructureHandle); vanillaSwap.setPricingEngine(swapPricingEngine); yieldTermStructureHandle.linkTo(yieldTermStructure); double swapNPV = vanillaSwap.NPV(); double swapFixedNPV = vanillaSwap.fixedLegNPV(); double swapFloatNPV = vanillaSwap.floatingLegNPV(); double bondFixedNPV = fixedBond.NPV(); double bondFloatNPV = floatBond.NPV(); int w = (swapType == VanillaSwap.Type.Receiver ? 1 : -1); double asBondsMarketValue = w * (bondFixedNPV - bondFloatNPV); double asBondsMarketValueNoAcc = w * (fixedBond.cleanPrice() - floatBond.cleanPrice()) / 100.0 * nominal; double asBondsAccruedInterest = asBondsMarketValue - asBondsMarketValueNoAcc; Console.WriteLine("Vanilla Swap Maket Value : {0:N}", swapNPV); Console.WriteLine("As Bonds Market Value : {0:N}", asBondsMarketValue); Console.WriteLine("As Bonds Market Value (no acc): {0:N}", asBondsMarketValueNoAcc); Console.WriteLine("As Bonds Accrued Interest : {0:N}", asBondsAccruedInterest); Date rollDate = new Date(1, Month.Nov, 2015); double bondFixedCash = 0; foreach (CashFlow cf in fixedBond.cashflows()) { if (cf.date() > rollDate & cf.date() <= _marketDate) { bondFixedCash += cf.amount(); } } double bondFloatCash = 0; foreach (CashFlow cf in floatBond.cashflows()) { if (cf.date() > rollDate & cf.date() <= _marketDate) { bondFloatCash += cf.amount(); } } double asBondsCash = w * (bondFixedCash - bondFloatCash); Console.WriteLine("As Bonds Settled Cash : {0:N}", asBondsCash); }