internal static global::System.Runtime.InteropServices.HandleRef getCPtr(BondFunctions obj) { return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr; }
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(BondFunctions obj) { return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr); }
static void Main(string[] args) { try { DateTime timer = DateTime.Now; int numberOfBonds = 15; double[] cleanPrice = new double[numberOfBonds]; for (int i = 0; i < numberOfBonds; i++) { cleanPrice[i] = 100.0; } List <SimpleQuote> quote = new List <SimpleQuote>(); for (int i = 0; i < numberOfBonds; i++) { SimpleQuote cp = new SimpleQuote(cleanPrice[i]); quote.Add(cp); } RelinkableHandle <Quote>[] quoteHandle = new RelinkableHandle <Quote> [numberOfBonds]; for (int i = 0; i < numberOfBonds; i++) { quoteHandle[i] = new RelinkableHandle <Quote>(); quoteHandle[i].linkTo(quote[i]); } int[] lengths = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 }; double[] coupons = { 0.0200, 0.0225, 0.0250, 0.0275, 0.0300, 0.0325, 0.0350, 0.0375, 0.0400, 0.0425, 0.0450, 0.0475, 0.0500, 0.0525, 0.0550 }; Frequency frequency = Frequency.Annual; DayCounter dc = new SimpleDayCounter(); BusinessDayConvention accrualConvention = BusinessDayConvention.ModifiedFollowing; BusinessDayConvention convention = BusinessDayConvention.ModifiedFollowing; double redemption = 100.0; Calendar calendar = new TARGET(); Date today = calendar.adjust(Date.Today); Date origToday = today; Settings.setEvaluationDate(today); // changing bondSettlementDays=3 increases calculation // time of exponentialsplines fitting method int bondSettlementDays = 0; int curveSettlementDays = 0; Date bondSettlementDate = calendar.advance(today, new Period(bondSettlementDays, TimeUnit.Days)); Console.WriteLine(); Console.WriteLine("Today's date: " + today); Console.WriteLine("Bonds' settlement date: " + bondSettlementDate); Console.WriteLine("Calculating fit for 15 bonds.....\n"); List <BondHelper> instrumentsA = new List <BondHelper>(); List <RateHelper> instrumentsB = new List <RateHelper>(); for (int j = 0; j < lengths.Length; j++) { Date maturity = calendar.advance(bondSettlementDate, new Period(lengths[j], TimeUnit.Years)); Schedule schedule = new Schedule(bondSettlementDate, maturity, new Period(frequency), calendar, accrualConvention, accrualConvention, DateGeneration.Rule.Backward, false); BondHelper helperA = new FixedRateBondHelper(quoteHandle[j], bondSettlementDays, 100.0, schedule, new InitializedList <double>(1, coupons[j]), dc, convention, redemption); RateHelper helperB = new FixedRateBondHelper(quoteHandle[j], bondSettlementDays, 100.0, schedule, new InitializedList <double>(1, coupons[j]), dc, convention, redemption); instrumentsA.Add(helperA); instrumentsB.Add(helperB); } bool constrainAtZero = true; double tolerance = 1.0e-10; int max = 5000; YieldTermStructure ts0 = new PiecewiseYieldCurve <Discount, LogLinear>(curveSettlementDays, calendar, instrumentsB, dc); ExponentialSplinesFitting exponentialSplines = new ExponentialSplinesFitting(constrainAtZero); FittedBondDiscountCurve ts1 = new FittedBondDiscountCurve(curveSettlementDays, calendar, instrumentsA, dc, exponentialSplines, tolerance, max); printOutput("(a) exponential splines", ts1); SimplePolynomialFitting simplePolynomial = new SimplePolynomialFitting(3, constrainAtZero); FittedBondDiscountCurve ts2 = new FittedBondDiscountCurve(curveSettlementDays, calendar, instrumentsA, dc, simplePolynomial, tolerance, max); printOutput("(b) simple polynomial", ts2); NelsonSiegelFitting nelsonSiegel = new NelsonSiegelFitting(); FittedBondDiscountCurve ts3 = new FittedBondDiscountCurve(curveSettlementDays, calendar, instrumentsA, dc, nelsonSiegel, tolerance, max); printOutput("(c) Nelson-Siegel", ts3); // a cubic bspline curve with 11 knot points, implies // n=6 (constrained problem) basis functions double[] knots = { -30.0, -20.0, 0.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 40.0, 50.0 }; List <double> knotVector = new List <double>(); for (int i = 0; i < knots.Length; i++) { knotVector.Add(knots[i]); } CubicBSplinesFitting cubicBSplines = new CubicBSplinesFitting(knotVector, constrainAtZero); FittedBondDiscountCurve ts4 = new FittedBondDiscountCurve(curveSettlementDays, calendar, instrumentsA, dc, cubicBSplines, tolerance, max); printOutput("(d) cubic B-splines", ts4); SvenssonFitting svensson = new SvenssonFitting(); FittedBondDiscountCurve ts5 = new FittedBondDiscountCurve(curveSettlementDays, calendar, instrumentsA, dc, svensson, tolerance, max); printOutput("(e) Svensson", ts5); Handle <YieldTermStructure> discountCurve = new Handle <YieldTermStructure>( new FlatForward(curveSettlementDays, calendar, 0.01, dc)); SpreadFittingMethod nelsonSiegelSpread = new SpreadFittingMethod(new NelsonSiegelFitting(), discountCurve); FittedBondDiscountCurve ts6 = new FittedBondDiscountCurve(curveSettlementDays, calendar, instrumentsA, dc, nelsonSiegelSpread, tolerance, max); printOutput("(f) Nelson-Siegel spreaded", ts6); Console.WriteLine("Output par rates for each curve. In this case, "); Console.WriteLine("par rates should equal coupons for these par bonds.\n"); Console.WriteLine(" tenor" + " | " + "coupon" + " | " + "bstrap" + " | " + " (a)" + " | " + " (b)" + " | " + " (c)" + " | " + " (d)" + " | " + " (e)" + " | " + " (f)"); for (int i = 0; i < instrumentsA.Count; i++) { List <CashFlow> cfs = instrumentsA[i].bond().cashflows(); int cfSize = instrumentsA[i].bond().cashflows().Count; List <Date> keyDates = new List <Date>(); keyDates.Add(bondSettlementDate); for (int j = 0; j < cfSize - 1; j++) { if (!cfs[j].hasOccurred(bondSettlementDate, false)) { Date myDate = cfs[j].date(); keyDates.Add(myDate); } } double tenor = dc.yearFraction(today, cfs[cfSize - 1].date()); double test = parRate(ts0, keyDates, dc); Console.WriteLine(tenor.ToString("##.000").PadLeft(6) + " | " + (100.0 * coupons[i]).ToString("##.000").PadLeft(6) + " | " // piecewise bootstrap + (100.0 * parRate(ts0, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // exponential splines + (100.0 * parRate(ts1, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // simple polynomial + (100.0 * parRate(ts2, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // Nelson-Siegel + (100.0 * parRate(ts3, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // cubic bsplines + (100.0 * parRate(ts4, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // Svensson + (100.0 * parRate(ts5, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // Nelson-Siegel Spreaded + (100.0 * parRate(ts6, keyDates, dc)).ToString("##.000").PadLeft(6)); } Console.WriteLine("\n\n"); Console.WriteLine("Now add 23 months to today. Par rates should be "); Console.WriteLine("automatically recalculated because today's date "); Console.WriteLine("changes. Par rates will NOT equal coupons (YTM "); Console.WriteLine("will, with the correct compounding), but the "); Console.WriteLine("piecewise yield curve par rates can be used as "); Console.WriteLine("a benchmark for correct par rates."); Console.WriteLine(); today = calendar.advance(origToday, 23, TimeUnit.Months, convention); Settings.setEvaluationDate(today); bondSettlementDate = calendar.advance(today, new Period(bondSettlementDays, TimeUnit.Days)); printOutput("(a) exponential splines", ts1); printOutput("(b) simple polynomial", ts2); printOutput("(c) Nelson-Siegel", ts3); printOutput("(d) cubic B-splines", ts4); printOutput("(e) Svensson", ts5); printOutput("(f) Nelson-Siegel spreaded", ts6); Console.WriteLine("\n"); Console.WriteLine(" tenor" + " | " + "coupon" + " | " + "bstrap" + " | " + " (a)" + " | " + " (b)" + " | " + " (c)" + " | " + " (d)" + " | " + " (e)" + " | " + " (f)"); for (int i = 0; i < instrumentsA.Count; i++) { List <CashFlow> cfs = instrumentsA[i].bond().cashflows(); int cfSize = instrumentsA[i].bond().cashflows().Count; List <Date> keyDates = new List <Date>(); keyDates.Add(bondSettlementDate); for (int j = 0; j < cfSize - 1; j++) { if (!cfs[j].hasOccurred(bondSettlementDate, false)) { Date myDate = cfs[j].date(); keyDates.Add(myDate); } } double tenor = dc.yearFraction(today, cfs[cfSize - 1].date()); double test = parRate(ts0, keyDates, dc); Console.WriteLine(tenor.ToString("##.000").PadLeft(6) + " | " + (100.0 * coupons[i]).ToString("#.000").PadLeft(6) + " | " // piecewise bootstrap + (100.0 * parRate(ts0, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // exponential splines + (100.0 * parRate(ts1, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // simple polynomial + (100.0 * parRate(ts2, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // Nelson-Siegel + (100.0 * parRate(ts3, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // cubic bsplines + (100.0 * parRate(ts4, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // Svensson + (100.0 * parRate(ts5, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // Nelson-Siegel Spreaded + (100.0 * parRate(ts6, keyDates, dc)).ToString("##.000").PadLeft(6)); } Console.WriteLine("\n\n"); Console.WriteLine("Now add one more month, for a total of two years "); Console.WriteLine("from the original date. The first instrument is "); Console.WriteLine("now expired and par rates should again equal "); Console.WriteLine("coupon values, since clean prices did not change."); Console.WriteLine("\n"); instrumentsA.RemoveRange(0, 1); // TODO instrumentsB.RemoveRange(0, 1); // TODO today = calendar.advance(origToday, 24, TimeUnit.Months, convention); Settings.setEvaluationDate(today); bondSettlementDate = calendar.advance(today, new Period(bondSettlementDays, TimeUnit.Days)); YieldTermStructure ts00 = new PiecewiseYieldCurve <Discount, LogLinear>(curveSettlementDays, calendar, instrumentsB, dc); FittedBondDiscountCurve ts11 = new FittedBondDiscountCurve(curveSettlementDays, calendar, instrumentsA, dc, exponentialSplines, tolerance, max); printOutput("(a) exponential splines", ts11); FittedBondDiscountCurve ts22 = new FittedBondDiscountCurve(curveSettlementDays, calendar, instrumentsA, dc, simplePolynomial, tolerance, max); printOutput("(b) simple polynomial", ts22); FittedBondDiscountCurve ts33 = new FittedBondDiscountCurve(curveSettlementDays, calendar, instrumentsA, dc, nelsonSiegel, tolerance, max); printOutput("(c) Nelson-Siegel", ts33); FittedBondDiscountCurve ts44 = new FittedBondDiscountCurve(curveSettlementDays, calendar, instrumentsA, dc, cubicBSplines, tolerance, max); printOutput("(d) cubic B-splines", ts44); FittedBondDiscountCurve ts55 = new FittedBondDiscountCurve(curveSettlementDays, calendar, instrumentsA, dc, svensson, tolerance, max); printOutput("(e) Svensson", ts55); FittedBondDiscountCurve ts66 = new FittedBondDiscountCurve(curveSettlementDays, calendar, instrumentsA, dc, nelsonSiegelSpread, tolerance, max); printOutput("(f) Nelson-Siegel spreaded", ts66); Console.WriteLine(" tenor" + " | " + "coupon" + " | " + "bstrap" + " | " + " (a)" + " | " + " (b)" + " | " + " (c)" + " | " + " (d)" + " | " + " (e)" + " | " + " (f)"); for (int i = 0; i < instrumentsA.Count; i++) { List <CashFlow> cfs = instrumentsA[i].bond().cashflows(); int cfSize = instrumentsA[i].bond().cashflows().Count; List <Date> keyDates = new List <Date>(); keyDates.Add(bondSettlementDate); for (int j = 0; j < cfSize - 1; j++) { if (!cfs[j].hasOccurred(bondSettlementDate, false)) { Date myDate = cfs[j].date(); keyDates.Add(myDate); } } double tenor = dc.yearFraction(today, cfs[cfSize - 1].date()); Console.WriteLine(tenor.ToString("##.000").PadLeft(6) + " | " + (100.0 * coupons[i + 1]).ToString("##.000").PadLeft(6) + " | " // piecewise bootstrap + (100.0 * parRate(ts00, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // exponential splines + (100.0 * parRate(ts11, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // simple polynomial + (100.0 * parRate(ts22, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // Nelson-Siegel + (100.0 * parRate(ts33, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // cubic bsplines + (100.0 * parRate(ts44, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // Svensson + (100.0 * parRate(ts55, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // Nelson-Siegel Spreaded + (100.0 * parRate(ts66, keyDates, dc)).ToString("##.000").PadLeft(6)); } Console.WriteLine("\n\n"); Console.WriteLine("Now decrease prices by a small amount, corresponding"); Console.WriteLine("to a theoretical five basis point parallel + shift of"); Console.WriteLine("the yield curve. Because bond quotes change, the new "); Console.WriteLine("par rates should be recalculated automatically."); Console.WriteLine("\n"); for (int k = 0; k < lengths.Length - 1; k++) { double P = instrumentsA[k].quote().link.value(); Bond b = instrumentsA[k].bond(); double ytm = BondFunctions.yield(b, P, dc, Compounding.Compounded, frequency, today); double dur = BondFunctions.duration(b, ytm, dc, Compounding.Compounded, frequency, Duration.Type.Modified, today); const double bpsChange = 5.0; // dP = -dur * P * dY double deltaP = -dur * P * (bpsChange / 10000.0); quote[k + 1].setValue(P + deltaP); } Console.WriteLine(" tenor" + " | " + "coupon" + " | " + "bstrap" + " | " + " (a)" + " | " + " (b)" + " | " + " (c)" + " | " + " (d)" + " | " + " (e)" + " | " + " (f)"); for (int i = 0; i < instrumentsA.Count; i++) { List <CashFlow> cfs = instrumentsA[i].bond().cashflows(); int cfSize = instrumentsA[i].bond().cashflows().Count; List <Date> keyDates = new List <Date>(); keyDates.Add(bondSettlementDate); for (int j = 0; j < cfSize - 1; j++) { if (!cfs[j].hasOccurred(bondSettlementDate, false)) { Date myDate = cfs[j].date(); keyDates.Add(myDate); } } double tenor = dc.yearFraction(today, cfs[cfSize - 1].date()); Console.WriteLine(tenor.ToString("##.000").PadLeft(6) + " | " + (100.0 * coupons[i + 1]).ToString("##.000").PadLeft(6) + " | " // piecewise bootstrap + (100.0 * parRate(ts00, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // exponential splines + (100.0 * parRate(ts11, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // simple polynomial + (100.0 * parRate(ts22, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // Nelson-Siegel + (100.0 * parRate(ts33, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // cubic bsplines + (100.0 * parRate(ts44, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // Svensson + (100.0 * parRate(ts55, keyDates, dc)).ToString("##.000").PadLeft(6) + " | " // Nelson-Siegel Spreaded + (100.0 * parRate(ts66, keyDates, dc)).ToString("##.000").PadLeft(6)); } Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.WriteLine(); Console.Write("Press any key to continue ..."); Console.ReadKey(); } catch (Exception e) { Console.WriteLine(e.Message); return; } }
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(); } }