//double fixedRate = 0.001; //double notional = 10000.0; //double recoveryRate = 0.4; //////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Calculates the cds. </summary> /// /// <param name="msg"> [in,out] The message. </param> /// <param name="fixedRate"> The fixed rate. </param> /// <param name="notional"> The notional. </param> /// <param name="recoveryRate"> The recovery rate. </param> /// /// <returns> True if it succeeds, false if it fails. </returns> //////////////////////////////////////////////////////////////////////////////////////////////////// public bool CalcCDS(ref CreditDefaultSwapRequestMessage msg, double fixedRate, double notional, double recoveryRate) { // Testing fair-spread calculation for credit-default swaps... using (SavedSettings backup = new SavedSettings()) { // Initialize curves Calendar calendar = new TARGET(); Date today = calendar.adjust(Date.Today); Settings.setEvaluationDate(today); Handle <Quote> hazardRate = new Handle <Quote>(new SimpleQuote(0.01234)); RelinkableHandle <DefaultProbabilityTermStructure> probabilityCurve = new RelinkableHandle <DefaultProbabilityTermStructure>(); probabilityCurve.linkTo(new FlatHazardRate(0, calendar, hazardRate, new Actual360())); RelinkableHandle <YieldTermStructure> discountCurve = new RelinkableHandle <YieldTermStructure>(); discountCurve.linkTo(new FlatForward(today, 0.06, new Actual360())); // Build the schedule Date issueDate = calendar.advance(today, -1, TimeUnit.Years); Date maturity = calendar.advance(issueDate, 10, TimeUnit.Years); BusinessDayConvention convention = BusinessDayConvention.Following; Schedule schedule = new MakeSchedule().from(issueDate) .to(maturity) .withFrequency(Frequency.Quarterly) .withCalendar(calendar) .withTerminationDateConvention(convention) .withRule(DateGeneration.Rule.TwentiethIMM).value(); // Build the CDS DayCounter dayCount = new Actual360(); IPricingEngine engine = new MidPointCdsEngine(probabilityCurve, recoveryRate, discountCurve); CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, notional, fixedRate, schedule, convention, dayCount, true, true); cds.setPricingEngine(engine); double fairRate = cds.fairSpread(); CreditDefaultSwap fairCds = new CreditDefaultSwap(Protection.Side.Seller, notional, fairRate, schedule, convention, dayCount, true, true); fairCds.setPricingEngine(engine); double fairNPV = fairCds.NPV(); double tolerance = 1e-10; msg.fairRate = fairRate; msg.fairNPV = fairNPV; return(Math.Abs(fairNPV) <= tolerance); } }
public void testFlatHazardRate() { // Testing flat hazard rate... double hazardRate = 0.0100; Handle <Quote> hazardRateQuote = new Handle <Quote>(new SimpleQuote(hazardRate)); DayCounter dayCounter = new Actual360(); Calendar calendar = new TARGET(); int n = 20; double tolerance = 1.0e-10; Date today = Settings.evaluationDate(); Date startDate = today; Date endDate = startDate; FlatHazardRate flatHazardRate = new FlatHazardRate(today, hazardRateQuote, dayCounter); for (int i = 0; i < n; i++) { endDate = calendar.advance(endDate, 1, TimeUnit.Years); double t = dayCounter.yearFraction(startDate, endDate); double probability = 1.0 - Math.Exp(-hazardRate * t); double computedProbability = flatHazardRate.defaultProbability(t); if (Math.Abs(probability - computedProbability) > tolerance) { QAssert.Fail("Failed to reproduce probability for flat hazard rate\n" + " calculated probability: " + computedProbability + "\n" + " expected probability: " + probability); } } }
public void testCashedValues() { Date startDate = new Date(01, 03, 2007); Period period = new Period(360, TimeUnit.Months); Calendar calendar = new TARGET(); Date endDate = calendar.advance(startDate, period, BusinessDayConvention.Unadjusted); Schedule schedule = new Schedule(startDate, endDate, new Period(1, TimeUnit.Months), calendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); // PSA 100% PSACurve psa100 = new PSACurve(startDate); double[] listCPR = { 0.2000, 0.4000, 0.6000, 0.8000, 1.0000, 1.2000, 1.4000, 1.6000, 1.8000, 2.0000, 2.2000, 2.4000, 2.6000, 2.8000, 3.0000, 3.2000, 3.4000, 3.6000, 3.8000, 4.0000, 4.2000, 4.4000, 4.6000, 4.8000, 5.0000, 5.2000, 5.4000, 5.6000, 5.8000, 6.0000 }; for (int i = 0; i < schedule.Count; i++) { if (i <= 29) { QAssert.AreEqual(listCPR[i], psa100.getCPR(schedule[i]) * 100, 0.001); } else { QAssert.AreEqual(6.0000, psa100.getCPR(schedule[i]) * 100); } } }
public void testImpliedHazardRate() { // Testing implied hazard-rate for credit-default swaps... using (SavedSettings backup = new SavedSettings()) { // Initialize curves Calendar calendar = new TARGET(); Date today = calendar.adjust(Date.Today); Settings.setEvaluationDate(today); double h1 = 0.30, h2 = 0.40; DayCounter dayCounter = new Actual365Fixed(); List <Date> dates = new List <Date>(3); List <double> hazardRates = new List <double>(3); dates.Add(today); hazardRates.Add(h1); dates.Add(today + new Period(5, TimeUnit.Years)); hazardRates.Add(h1); dates.Add(today + new Period(10, TimeUnit.Years)); hazardRates.Add(h2); RelinkableHandle <DefaultProbabilityTermStructure> probabilityCurve = new RelinkableHandle <DefaultProbabilityTermStructure>(); probabilityCurve.linkTo(new InterpolatedHazardRateCurve <BackwardFlat>(dates, hazardRates, dayCounter)); RelinkableHandle <YieldTermStructure> discountCurve = new RelinkableHandle <YieldTermStructure>(); discountCurve.linkTo(new FlatForward(today, 0.03, new Actual360())); Frequency frequency = Frequency.Semiannual; BusinessDayConvention convention = BusinessDayConvention.ModifiedFollowing; Date issueDate = calendar.advance(today, -6, TimeUnit.Months); double fixedRate = 0.0120; DayCounter cdsDayCount = new Actual360(); double notional = 10000.0; double recoveryRate = 0.4; double?latestRate = null; for (int n = 6; n <= 10; ++n) { Date maturity = calendar.advance(issueDate, n, TimeUnit.Years); Schedule schedule = new Schedule(issueDate, maturity, new Period(frequency), calendar, convention, convention, DateGeneration.Rule.Forward, false); CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, notional, fixedRate, schedule, convention, cdsDayCount, true, true); cds.setPricingEngine(new MidPointCdsEngine(probabilityCurve, recoveryRate, discountCurve)); double NPV = cds.NPV(); double flatRate = cds.impliedHazardRate(NPV, discountCurve, dayCounter, recoveryRate); if (flatRate < h1 || flatRate > h2) { Assert.Fail("implied hazard rate outside expected range\n" + " maturity: " + n + " years\n" + " expected minimum: " + h1 + "\n" + " expected maximum: " + h2 + "\n" + " implied rate: " + flatRate); } if (n > 6 && flatRate < latestRate) { Assert.Fail("implied hazard rate decreasing with swap maturity\n" + " maturity: " + n + " years\n" + " previous rate: " + latestRate + "\n" + " implied rate: " + flatRate); } latestRate = flatRate; RelinkableHandle <DefaultProbabilityTermStructure> probability = new RelinkableHandle <DefaultProbabilityTermStructure>(); probability.linkTo(new FlatHazardRate(today, new Handle <Quote>(new SimpleQuote(flatRate)), dayCounter)); CreditDefaultSwap cds2 = new CreditDefaultSwap(Protection.Side.Seller, notional, fixedRate, schedule, convention, cdsDayCount, true, true); cds2.setPricingEngine(new MidPointCdsEngine(probability, recoveryRate, discountCurve)); double NPV2 = cds2.NPV(); double tolerance = 1.0; if (Math.Abs(NPV - NPV2) > tolerance) { Assert.Fail("failed to reproduce NPV with implied rate\n" + " expected: " + NPV + "\n" + " calculated: " + NPV2); } } } }
public void testDefaultProbability() { // Testing default-probability structure... double hazardRate = 0.0100; Handle <Quote> hazardRateQuote = new Handle <Quote>(new SimpleQuote(hazardRate)); DayCounter dayCounter = new Actual360(); Calendar calendar = new TARGET(); int n = 20; double tolerance = 1.0e-10; Date today = Settings.evaluationDate(); Date startDate = today; Date endDate = startDate; FlatHazardRate flatHazardRate = new FlatHazardRate(startDate, hazardRateQuote, dayCounter); for (int i = 0; i < n; i++) { startDate = endDate; endDate = calendar.advance(endDate, 1, TimeUnit.Years); double pStart = flatHazardRate.defaultProbability(startDate); double pEnd = flatHazardRate.defaultProbability(endDate); double pBetweenComputed = flatHazardRate.defaultProbability(startDate, endDate); double pBetween = pEnd - pStart; if (Math.Abs(pBetween - pBetweenComputed) > tolerance) { QAssert.Fail("Failed to reproduce probability(d1, d2) " + "for default probability structure\n" + " calculated probability: " + pBetweenComputed + "\n" + " expected probability: " + pBetween); } double t2 = dayCounter.yearFraction(today, endDate); double timeProbability = flatHazardRate.defaultProbability(t2); double dateProbability = flatHazardRate.defaultProbability(endDate); if (Math.Abs(timeProbability - dateProbability) > tolerance) { QAssert.Fail("single-time probability and single-date probability do not match\n" + " time probability: " + timeProbability + "\n" + " date probability: " + dateProbability); } double t1 = dayCounter.yearFraction(today, startDate); timeProbability = flatHazardRate.defaultProbability(t1, t2); dateProbability = flatHazardRate.defaultProbability(startDate, endDate); if (Math.Abs(timeProbability - dateProbability) > tolerance) { QAssert.Fail("double-time probability and double-date probability do not match\n" + " time probability: " + timeProbability + "\n" + " date probability: " + dateProbability); } } }
public void testSwaps() { //BOOST_MESSAGE("Testing Hull-White swap pricing against known values..."); Date today; //=Settings::instance().evaluationDate();; Calendar calendar = new TARGET(); today = calendar.adjust(Date.Today); Settings.setEvaluationDate(today); Date settlement = calendar.advance(today, 2, TimeUnit.Days); Date[] dates = { settlement, calendar.advance(settlement, 1, TimeUnit.Weeks), calendar.advance(settlement, 1, TimeUnit.Months), calendar.advance(settlement, 3, TimeUnit.Months), calendar.advance(settlement, 6, TimeUnit.Months), calendar.advance(settlement, 9, TimeUnit.Months), calendar.advance(settlement, 1, TimeUnit.Years), calendar.advance(settlement, 2, TimeUnit.Years), calendar.advance(settlement, 3, TimeUnit.Years), calendar.advance(settlement, 5, TimeUnit.Years), calendar.advance(settlement, 10, TimeUnit.Years), calendar.advance(settlement, 15, TimeUnit.Years) }; double[] discounts = { 1.0, 0.999258, 0.996704, 0.990809, 0.981798, 0.972570, 0.963430, 0.929532, 0.889267, 0.803693, 0.596903, 0.433022 }; //for (int i = 0; i < dates.Length; i++) // dates[i] + dates.Length; LogLinear Interpolator = new LogLinear(); Handle <YieldTermStructure> termStructure = new Handle <YieldTermStructure>( new InterpolatedDiscountCurve <LogLinear>( dates.ToList <Date>(), discounts.ToList <double>(), new Actual365Fixed(), new Calendar(), null, null, Interpolator) ); HullWhite model = new HullWhite(termStructure); int[] start = { -3, 0, 3 }; int[] length = { 2, 5, 10 }; double[] rates = { 0.02, 0.04, 0.06 }; IborIndex euribor = new Euribor6M(termStructure); IPricingEngine engine = new TreeVanillaSwapEngine(model, 120, termStructure); #if QL_USE_INDEXED_COUPON double tolerance = 4.0e-3; #else double tolerance = 1.0e-8; #endif for (int i = 0; i < start.Length; i++) { Date startDate = calendar.advance(settlement, start[i], TimeUnit.Months); if (startDate < today) { Date fixingDate = calendar.advance(startDate, -2, TimeUnit.Days); //TimeSeries<double> pastFixings; ObservableValue <TimeSeries <double> > pastFixings = new ObservableValue <TimeSeries <double> >(); pastFixings.value()[fixingDate] = 0.03; IndexManager.instance().setHistory(euribor.name(), pastFixings); } for (int j = 0; j < length.Length; j++) { Date maturity = calendar.advance(startDate, length[i], TimeUnit.Years); Schedule fixedSchedule = new Schedule(startDate, maturity, new Period(Frequency.Annual), calendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Forward, false); Schedule floatSchedule = new Schedule(startDate, maturity, new Period(Frequency.Semiannual), calendar, BusinessDayConvention.Following, BusinessDayConvention.Following, DateGeneration.Rule.Forward, false); for (int k = 0; k < rates.Length; k++) { VanillaSwap swap = new VanillaSwap(VanillaSwap.Type.Payer, 1000000.0, fixedSchedule, rates[k], new Thirty360(), floatSchedule, euribor, 0.0, new Actual360()); swap.setPricingEngine(new DiscountingSwapEngine(termStructure)); double expected = swap.NPV(); swap.setPricingEngine(engine); double calculated = swap.NPV(); double error = Math.Abs((expected - calculated) / expected); if (error > tolerance) { Assert.Fail("Failed to reproduce swap NPV:" //+ QL_FIXED << std::setprecision(9) + "\n calculated: " + calculated + "\n expected: " + expected //+ QL_SCIENTIFIC + "\n rel. error: " + error); } } } } }
private static void Main() { DateTime startTime = DateTime.Now; var todaysDate = new DateTime(2002, 2, 15); Settings.instance().setEvaluationDate(todaysDate); Calendar calendar = new TARGET(); var settlementDate = new Date(19, Month.February, 2002); // flat yield term structure impling 1x5 swap at 5% Quote flatRate = new SimpleQuote(0.04875825); var myTermStructure = new FlatForward(settlementDate, new QuoteHandle(flatRate), new Actual365Fixed()); var rhTermStructure = new RelinkableYieldTermStructureHandle(); rhTermStructure.linkTo(myTermStructure); // Define the ATM/OTM/ITM swaps var fixedLegTenor = new Period(1, TimeUnit.Years); const BusinessDayConvention fixedLegConvention = BusinessDayConvention.Unadjusted; const BusinessDayConvention floatingLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter fixedLegDayCounter = new Thirty360(Thirty360.Convention.European); var floatingLegTenor = new Period(6, TimeUnit.Months); const double dummyFixedRate = 0.03; IborIndex indexSixMonths = new Euribor6M(rhTermStructure); Date startDate = calendar.advance(settlementDate, 1, TimeUnit.Years, floatingLegConvention); Date maturity = calendar.advance(startDate, 5, TimeUnit.Years, floatingLegConvention); var fixedSchedule = new Schedule(startDate, maturity, fixedLegTenor, calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false); var floatSchedule = new Schedule(startDate, maturity, floatingLegTenor, calendar, floatingLegConvention, floatingLegConvention, DateGeneration.Rule.Forward, false); var swap = new VanillaSwap(VanillaSwap.Type.Payer, 1000.0, fixedSchedule, dummyFixedRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); var swapEngine = new DiscountingSwapEngine(rhTermStructure); swap.setPricingEngine(swapEngine); double fixedAtmRate = swap.fairRate(); double fixedOtmRate = fixedAtmRate * 1.2; double fixedItmRate = fixedAtmRate * 0.8; var atmSwap = new VanillaSwap(VanillaSwap.Type.Payer, 1000.0, fixedSchedule, fixedAtmRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); var otmSwap = new VanillaSwap(VanillaSwap.Type.Payer, 1000.0, fixedSchedule, fixedOtmRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); var itmSwap = new VanillaSwap(VanillaSwap.Type.Payer, 1000.0, fixedSchedule, fixedItmRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); atmSwap.setPricingEngine(swapEngine); otmSwap.setPricingEngine(swapEngine); itmSwap.setPricingEngine(swapEngine); // defining the swaptions to be used in model calibration var swaptionMaturities = new PeriodVector { new Period(1, TimeUnit.Years), new Period(2, TimeUnit.Years), new Period(3, TimeUnit.Years), new Period(4, TimeUnit.Years), new Period(5, TimeUnit.Years) }; var swaptions = new CalibrationHelperVector(); // List of times that have to be included in the timegrid var times = new DoubleVector(); for (int i = 0; i < NUM_ROWS; i++) { int j = NUM_COLS - i - 1; // 1x5, 2x4, 3x3, 4x2, 5x1 int k = i * NUM_COLS + j; Quote vol = new SimpleQuote(SWAPTION_VOLS[k]); var helper = new SwaptionHelper(swaptionMaturities[i], new Period(SWAP_LENGHTS[j], TimeUnit.Years), new QuoteHandle(vol), indexSixMonths, indexSixMonths.tenor(), indexSixMonths.dayCounter(), indexSixMonths.dayCounter(), rhTermStructure); swaptions.Add(helper); times.AddRange(helper.times()); } // Building time-grid var grid = new TimeGrid(times, 30); // defining the models // G2 modelG2 = new G2(rhTermStructure)); var modelHw = new HullWhite(rhTermStructure); var modelHw2 = new HullWhite(rhTermStructure); var modelBk = new BlackKarasinski(rhTermStructure); // model calibrations Console.WriteLine("Hull-White (analytic formulae) calibration"); foreach (CalibrationHelper calibrationHelper in swaptions) { NQuantLibc.as_black_helper(calibrationHelper).setPricingEngine(new JamshidianSwaptionEngine(modelHw)); } CalibrateModel(modelHw, swaptions, 0.05); Console.WriteLine("Hull-White (numerical) calibration"); foreach (CalibrationHelper calibrationHelper in swaptions) { NQuantLibc.as_black_helper(calibrationHelper).setPricingEngine(new TreeSwaptionEngine(modelHw2, grid)); } CalibrateModel(modelHw2, swaptions, 0.05); Console.WriteLine("Black-Karasinski (numerical) calibration"); foreach (CalibrationHelper calibrationHelper in swaptions) { NQuantLibc.as_black_helper(calibrationHelper).setPricingEngine(new TreeSwaptionEngine(modelBk, grid)); } CalibrateModel(modelBk, swaptions, 0.05); // ATM Bermudan swaption pricing Console.WriteLine("Payer bermudan swaption struck at {0} (ATM)", fixedAtmRate); var bermudanDates = new DateVector(); var schedule = new Schedule(startDate, maturity, new Period(3, TimeUnit.Months), calendar, BusinessDayConvention.Following, BusinessDayConvention.Following, DateGeneration.Rule.Forward, false); for (uint i = 0; i < schedule.size(); i++) { bermudanDates.Add(schedule.date(i)); } Exercise bermudaExercise = new BermudanExercise(bermudanDates); var bermudanSwaption = new Swaption(atmSwap, bermudaExercise); bermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw, 50)); Console.WriteLine("HW: " + bermudanSwaption.NPV()); bermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw2, 50)); Console.WriteLine("HW (num): " + bermudanSwaption.NPV()); bermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelBk, 50)); Console.WriteLine("BK (num): " + bermudanSwaption.NPV()); DateTime endTime = DateTime.Now; TimeSpan delta = endTime - startTime; Console.WriteLine(); Console.WriteLine("Run completed in {0} s", delta.TotalSeconds); Console.WriteLine(); }
static void Main(string[] args) { DateTime timer = DateTime.Now; //////////////// DATES ////////////////////////////////////////////// Calendar calendar = new TARGET(); Date todaysDate = new Date(15, Month.January, 2017); Date settlementDate = new Date(todaysDate); Settings.setEvaluationDate(todaysDate); DayCounter dayCounter = new Actual365Fixed(); //////////////// MARKET ////////////////////////////////////////////// // Spot double underlying = 4468.17; Handle <Quote> underlyingH = new Handle <Quote>(new SimpleQuote(underlying)); // riskfree double riskFreeRate = 0.035; Handle <YieldTermStructure> flatTermStructure = new Handle <YieldTermStructure>(new FlatForward(settlementDate, riskFreeRate, dayCounter)); // dividend double dividendYield = 0.0; double fixedDiv = 5.0; Handle <YieldTermStructure> flatDividendTS = new Handle <YieldTermStructure>(new FlatForward(settlementDate, dividendYield, dayCounter)); Handle <YieldTermStructure> FixedDivTermStructure = new Handle <YieldTermStructure>(new FixedForward(settlementDate, fixedDiv, underlying, dayCounter)); // vol surface Date StartDateVol = settlementDate + new Period(1, TimeUnit.Months); List <int> maturityInDays = new InitializedList <int>() { 0, 13, 41, 90, 165, 256, 345, 524, 703 }; List <Date> datesVol = new InitializedList <Date>(); for (int d = 1; d < maturityInDays.Count; d++) { datesVol.Add(calendar.advance(settlementDate, new Period(maturityInDays[d], TimeUnit.Days))); } List <double> strikes = new InitializedList <double>() { 3400, 3600, 3800, 4000, 4200, 4400, 4500, 4600, 4800, 5000, 5200, 5400, 5600 }; Matrix blackVolMatrix = new Matrix(maturityInDays.Count - 1, strikes.Count, 0.2); var vols = new InitializedList <double>() { 0.6625, 0.4875, 0.4204, 0.3667, 0.3431, 0.3267, 0.3121, 0.3121, 0.6007, 0.4543, 0.3967, 0.3511, 0.3279, 0.3154, 0.2984, 0.2921, 0.5084, 0.4221, 0.3718, 0.3327, 0.3155, 0.3027, 0.2919, 0.2889, 0.4541, 0.3869, 0.3492, 0.3149, 0.2963, 0.2926, 0.2819, 0.2800, 0.4060, 0.3607, 0.3330, 0.2999, 0.2887, 0.2811, 0.2751, 0.2775, 0.3726, 0.3396, 0.3108, 0.2781, 0.2788, 0.2722, 0.2661, 0.2686, 0.3550, 0.3277, 0.3012, 0.2781, 0.2781, 0.2661, 0.2661, 0.2681, 0.3428, 0.3209, 0.2958, 0.2740, 0.2688, 0.2627, 0.2580, 0.2620, 0.3302, 0.3062, 0.2799, 0.2631, 0.2573, 0.2533, 0.2504, 0.2544, 0.3343, 0.2959, 0.2705, 0.2540, 0.2504, 0.2464, 0.2448, 0.2462, 0.3460, 0.2845, 0.2624, 0.2463, 0.2425, 0.2385, 0.2373, 0.2422, 0.3857, 0.2860, 0.2578, 0.2399, 0.2357, 0.2327, 0.2312, 0.2351, 0.3976, 0.2860, 0.2607, 0.2356, 0.2297, 0.2268, 0.2241, 0.2320 }; for (int i = 0; i < vols.Count; i++) { int testraw = (int)(i % (datesVol.Count)); int testcol = (int)(i / (datesVol.Count)); blackVolMatrix[testraw, testcol] = vols[i]; } BlackVarianceSurface mySurface = new BlackVarianceSurface(settlementDate, calendar, datesVol, strikes, Matrix.transpose(blackVolMatrix), dayCounter); Handle <BlackVolTermStructure> mySurfaceH = new Handle <BlackVolTermStructure>(mySurface); //////////////// CALIBRATION ////////////////////////////////////////////// Period helperPeriod = new Period(); //helpers List <CalibrationHelper> calibrationHelpers = new List <CalibrationHelper>(); for (int k = 0; k < strikes.Count; k++) { for (int d = 0; d < datesVol.Count; d++) { helperPeriod = new Period(datesVol[d] - settlementDate, TimeUnit.Days); calibrationHelpers.Add(new HestonModelHelper(helperPeriod, calendar, underlying, strikes[k], new Handle <Quote>(new SimpleQuote(blackVolMatrix[d, k])), flatTermStructure, flatDividendTS, CalibrationHelper.CalibrationErrorType.ImpliedVolError)); } } // starting data double v0 = 0.1; double kappa = 1.0; double theta = 0.1; double sigma = 0.5; double rho = -0.5; // model HestonProcess hestonProcess = new HestonProcess(flatTermStructure, flatDividendTS, underlyingH, v0, kappa, theta, sigma, rho); HestonModel hestonmodel = new HestonModel(hestonProcess); AnalyticHestonEngine analyticHestonEngine = new AnalyticHestonEngine(hestonmodel); foreach (HestonModelHelper hmh in calibrationHelpers) { hmh.setPricingEngine(analyticHestonEngine); } // optimization double tolerance = 1.0e-8; LevenbergMarquardt optimizationmethod = new LevenbergMarquardt(tolerance, tolerance, tolerance); hestonmodel.calibrate(calibrationHelpers, optimizationmethod, new EndCriteria(400, 40, tolerance, tolerance, tolerance)); double error = 0.0; List <double> errorList = new InitializedList <double>(); //////////////// CALIBRATION RESULTS ////////////////////////////////////////////// Console.WriteLine("Calbration :"); Console.WriteLine("-----------"); foreach (HestonModelHelper hmh in calibrationHelpers) { error += Math.Abs(hmh.calibrationError()); errorList.Add(Math.Abs(hmh.calibrationError())); } Vector hestonParameters = hestonmodel.parameters(); Console.WriteLine("v0 = {0:0.00%}", hestonParameters[4]); Console.WriteLine("kappa = {0:0.00%}", hestonParameters[1]); Console.WriteLine("theta = {0:0.00%}", hestonParameters[0]); Console.WriteLine("sigma = {0:0.00%}", hestonParameters[2]); Console.WriteLine("rho = {0:0.00%}", hestonParameters[3]); Console.WriteLine(); Console.WriteLine("Total error = {0:0.0000}", error); Console.WriteLine("Mean error = {0:0.0000%}", error / (errorList.Count - 1)); Console.WriteLine(); int StepsPerYear = 52; double absoluteTolerance = 80.0; ulong mcSeed = 42; // MC Heston process HestonProcess calibratedHestonProcess = new HestonProcess(flatTermStructure, flatDividendTS, underlyingH, hestonParameters[4], hestonParameters[1], hestonParameters[0], hestonParameters[2], hestonParameters[3]); // BS process GeneralizedBlackScholesProcessTolerance bsmProcess = new GeneralizedBlackScholesProcessTolerance(underlyingH, FixedDivTermStructure, flatTermStructure, mySurfaceH); //////////////// ENGINES ///////////////////////////////////////////////// IPricingEngine mcHestonEngine = new MakeMCEuropeanHestonEngine <PseudoRandom, Statistics>(calibratedHestonProcess) .withStepsPerYear(StepsPerYear) .withAbsoluteTolerance(absoluteTolerance) .withSeed(mcSeed) .getAsPricingEngine(); double absoluteTolerance2 = 1.0; IPricingEngine mcGenHestonEngineTestbs = new MakeMCGenericScriptInstrument <PseudoRandom>(bsmProcess) .withStepsPerYear(StepsPerYear) .withAbsoluteTolerance(absoluteTolerance2) .withSeed(mcSeed) .value(); IPricingEngine mcGenHestonEngineTestbs2 = new MakeMCGenericScriptInstrument <PseudoRandom>(calibratedHestonProcess) .withStepsPerYear(StepsPerYear) .withAbsoluteTolerance(absoluteTolerance2) .withSeed(mcSeed) .value(); //////////////// PRICING ////////////////////////////////////////////// Console.WriteLine("Pricing Vanilla:"); Console.WriteLine("---------------"); Date maturity = new Date(17, Month.May, 2019); Exercise europeanExercise = new EuropeanExercise(maturity); Option.Type type = Option.Type.Call; double strike = underlying; StrikedTypePayoff payoff = new PlainVanillaPayoff(type, strike); VanillaOption europeanOption = new VanillaOption(payoff, europeanExercise); // heston europeanOption.setPricingEngine(analyticHestonEngine); Console.Write("Heston pricing = {0:0.0000}", europeanOption.NPV()); Console.WriteLine(" -> {0:0.0000%}", europeanOption.NPV() / underlying); // Mc heston europeanOption.setPricingEngine(mcHestonEngine); Console.Write("HestMC pricing = {0:0.0000}", europeanOption.NPV()); Console.Write(" -> {0:0.0000%}", europeanOption.NPV() / underlying); Console.WriteLine(" tolerance {0:0.0} / {1:0.00%}", absoluteTolerance, absoluteTolerance / underlying); // analytic bs europeanOption.setPricingEngine(new AnalyticEuropeanEngine(bsmProcess)); Console.Write("BS pricing = {0:0.0000}", europeanOption.NPV()); Console.WriteLine(" -> {0:0.0000%}", europeanOption.NPV() / underlying); Console.WriteLine(); //////////////// AUTOCALL HESTON ////////////////////////////////////////////// List <Date> fixingdates = new InitializedList <Date>(); double coupon = 0.05; double barrierlvl = 0.6; for (int i = 1; i <= 4; i++) { fixingdates.Add(settlementDate + new Period(i, TimeUnit.Years)); } ScriptGenericAutocall myGenericAutocallHTTEst = new ScriptGenericAutocall(fixingdates, coupon, barrierlvl, underlying); myGenericAutocallHTTEst.setPricingEngine(mcGenHestonEngineTestbs); Console.WriteLine("Pricing Autocall BS :"); Console.WriteLine("---------------------"); Console.WriteLine("test = {0:0.0000}", myGenericAutocallHTTEst.NPV()); Console.WriteLine("Err = {0:0.0000%}", myGenericAutocallHTTEst.errorEstimate() / myGenericAutocallHTTEst.NPV()); Console.WriteLine("Samples = {0}", myGenericAutocallHTTEst.samples()); Console.Write("\n"); for (int i = 0; i < 4; i++) { Console.WriteLine("ProbaCall {1} = {0:0.0000%}", myGenericAutocallHTTEst.inspout("ProbaCall " + i), i + 1); } Console.WriteLine("ProbaMid = {0:0.0000%}", myGenericAutocallHTTEst.inspout("ProbaMid")); Console.WriteLine("probaDown = {0:0.0000%}", myGenericAutocallHTTEst.inspout("ProbaDown")); Console.WriteLine("test = {0:0.0000%}", myGenericAutocallHTTEst.inspout("ProbaDown")); Console.WriteLine("AvgDown/Proba = {0:0.0000%}", myGenericAutocallHTTEst.inspout("AvgDown") / myGenericAutocallHTTEst.inspout("ProbaDown")); Console.Write("\n"); myGenericAutocallHTTEst.setPricingEngine(mcGenHestonEngineTestbs2); Console.WriteLine("Pricing Autocall Heston:"); Console.WriteLine("------------------------"); Console.WriteLine("test = {0:0.0000}", myGenericAutocallHTTEst.NPV()); Console.WriteLine("Err = {0:0.0000%}", myGenericAutocallHTTEst.errorEstimate() / myGenericAutocallHTTEst.NPV()); Console.WriteLine("Samples = {0}", myGenericAutocallHTTEst.samples()); Console.Write("\n"); for (int i = 0; i < 4; i++) { Console.WriteLine("ProbaCall {1} = {0:0.0000%}", myGenericAutocallHTTEst.inspout("ProbaCall " + i), i + 1); } Console.WriteLine("ProbaMid = {0:0.0000%}", myGenericAutocallHTTEst.inspout("ProbaMid")); Console.WriteLine("probaDown = {0:0.0000%}", myGenericAutocallHTTEst.inspout("ProbaDown")); Console.WriteLine("test = {0:0.0000%}", myGenericAutocallHTTEst.inspout("ProbaDown")); Console.WriteLine("AvgDown/Proba = {0:0.0000%}", myGenericAutocallHTTEst.inspout("AvgDown") / myGenericAutocallHTTEst.inspout("ProbaDown")); Console.Write("\n"); //////////////// END TEST ////////////////////////////////////////////// Console.WriteLine(); Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.WriteLine(); Console.Write("Press any key to continue ..."); Console.ReadKey(); }
static void Main(string[] args) { DateTime startTime = DateTime.Now; Date todaysDate = new Date(15, Month.February, 2002); Calendar calendar = new TARGET(); Date settlementDate = new Date(19, Month.February, 2002); Settings.instance().setEvaluationDate(todaysDate); // flat yield term structure impling 1x5 swap at 5% Quote flatRate = new SimpleQuote(0.04875825); FlatForward myTermStructure = new FlatForward( settlementDate, new QuoteHandle(flatRate), new Actual365Fixed()); RelinkableYieldTermStructureHandle rhTermStructure = new RelinkableYieldTermStructureHandle(); rhTermStructure.linkTo(myTermStructure); // Define the ATM/OTM/ITM swaps Period fixedLegTenor = new Period(1, TimeUnit.Years); BusinessDayConvention fixedLegConvention = BusinessDayConvention.Unadjusted; BusinessDayConvention floatingLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter fixedLegDayCounter = new Thirty360(Thirty360.Convention.European); Period floatingLegTenor = new Period(6, TimeUnit.Months); double dummyFixedRate = 0.03; IborIndex indexSixMonths = new Euribor6M(rhTermStructure); Date startDate = calendar.advance(settlementDate, 1, TimeUnit.Years, floatingLegConvention); Date maturity = calendar.advance(startDate, 5, TimeUnit.Years, floatingLegConvention); Schedule fixedSchedule = new Schedule(startDate, maturity, fixedLegTenor, calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false); Schedule floatSchedule = new Schedule(startDate, maturity, floatingLegTenor, calendar, floatingLegConvention, floatingLegConvention, DateGeneration.Rule.Forward, false); VanillaSwap swap = new VanillaSwap( VanillaSwap.Type.Payer, 1000.0, fixedSchedule, dummyFixedRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); DiscountingSwapEngine swapEngine = new DiscountingSwapEngine(rhTermStructure); swap.setPricingEngine(swapEngine); double fixedATMRate = swap.fairRate(); double fixedOTMRate = fixedATMRate * 1.2; double fixedITMRate = fixedATMRate * 0.8; VanillaSwap atmSwap = new VanillaSwap( VanillaSwap.Type.Payer, 1000.0, fixedSchedule, fixedATMRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); VanillaSwap otmSwap = new VanillaSwap( VanillaSwap.Type.Payer, 1000.0, fixedSchedule, fixedOTMRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); VanillaSwap itmSwap = new VanillaSwap( VanillaSwap.Type.Payer, 1000.0, fixedSchedule, fixedITMRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); atmSwap.setPricingEngine(swapEngine); otmSwap.setPricingEngine(swapEngine); itmSwap.setPricingEngine(swapEngine); // defining the swaptions to be used in model calibration PeriodVector swaptionMaturities = new PeriodVector(); swaptionMaturities.Add(new Period(1, TimeUnit.Years)); swaptionMaturities.Add(new Period(2, TimeUnit.Years)); swaptionMaturities.Add(new Period(3, TimeUnit.Years)); swaptionMaturities.Add(new Period(4, TimeUnit.Years)); swaptionMaturities.Add(new Period(5, TimeUnit.Years)); CalibrationHelperVector swaptions = new CalibrationHelperVector(); // List of times that have to be included in the timegrid DoubleVector times = new DoubleVector(); for (int i = 0; i < numRows; i++) { int j = numCols - i - 1; // 1x5, 2x4, 3x3, 4x2, 5x1 int k = i * numCols + j; Quote vol = new SimpleQuote(swaptionVols[k]); SwaptionHelper helper = new SwaptionHelper( swaptionMaturities[i], new Period(swapLengths[j], TimeUnit.Years), new QuoteHandle(vol), indexSixMonths, indexSixMonths.tenor(), indexSixMonths.dayCounter(), indexSixMonths.dayCounter(), rhTermStructure); swaptions.Add(helper); times.AddRange(helper.times()); } // Building time-grid TimeGrid grid = new TimeGrid(times, 30); // defining the models // G2 modelG2 = new G2(rhTermStructure)); HullWhite modelHW = new HullWhite(rhTermStructure); HullWhite modelHW2 = new HullWhite(rhTermStructure); BlackKarasinski modelBK = new BlackKarasinski(rhTermStructure); // model calibrations // Console.WriteLine( "G2 (analytic formulae) calibration" ); // for (int i=0; i<swaptions.Count; i++) // NQuantLibc.as_black_helper(swaptions[i]).setPricingEngine( // new G2SwaptionEngine( modelG2, 6.0, 16 ) ); // // calibrateModel( modelG2, swaptions, 0.05); // Console.WriteLine( "calibrated to:" ); // Console.WriteLine( "a = " + modelG2.parameters()[0] ); // Console.WriteLine( "sigma = " + modelG2.parameters()[1] ); // Console.WriteLine( "b = " + modelG2.parameters()[2] ); // Console.WriteLine( "eta = " + modelG2.parameters()[3] ); // Console.WriteLine( "rho = " + modelG2.parameters()[4] ); Console.WriteLine("Hull-White (analytic formulae) calibration"); for (int i = 0; i < swaptions.Count; i++) { NQuantLibc.as_black_helper(swaptions[i]).setPricingEngine( new JamshidianSwaptionEngine(modelHW)); } calibrateModel(modelHW, swaptions, 0.05); // Console.WriteLine( "calibrated to:" ); // Console.WriteLine( "a = " + modelHW.parameters()[0] ); // Console.WriteLine( "sigma = " + modelHW.parameters()[1] ); Console.WriteLine("Hull-White (numerical) calibration"); for (int i = 0; i < swaptions.Count; i++) { NQuantLibc.as_black_helper(swaptions[i]).setPricingEngine( new TreeSwaptionEngine(modelHW2, grid)); } calibrateModel(modelHW2, swaptions, 0.05); // std::cout << "calibrated to:\n" // << "a = " << modelHW2->params()[0] << ", " // << "sigma = " << modelHW2->params()[1] // << std::endl << std::endl; Console.WriteLine("Black-Karasinski (numerical) calibration"); for (int i = 0; i < swaptions.Count; i++) { NQuantLibc.as_black_helper(swaptions[i]).setPricingEngine( new TreeSwaptionEngine(modelBK, grid)); } calibrateModel(modelBK, swaptions, 0.05); // std::cout << "calibrated to:\n" // << "a = " << modelBK->params()[0] << ", " // << "sigma = " << modelBK->params()[1] // << std::endl << std::endl; // ATM Bermudan swaption pricing Console.WriteLine("Payer bermudan swaption struck at {0} (ATM)", fixedATMRate); DateVector bermudanDates = new DateVector(); Schedule schedule = new Schedule(startDate, maturity, new Period(3, TimeUnit.Months), calendar, BusinessDayConvention.Following, BusinessDayConvention.Following, DateGeneration.Rule.Forward, false); for (uint i = 0; i < schedule.size(); i++) { bermudanDates.Add(schedule.date(i)); } Exercise bermudaExercise = new BermudanExercise(bermudanDates); Swaption bermudanSwaption = new Swaption(atmSwap, bermudaExercise); bermudanSwaption.setPricingEngine( new TreeSwaptionEngine(modelHW, 50)); Console.WriteLine("HW: " + bermudanSwaption.NPV()); bermudanSwaption.setPricingEngine( new TreeSwaptionEngine(modelHW2, 50)); Console.WriteLine("HW (num): " + bermudanSwaption.NPV()); bermudanSwaption.setPricingEngine( new TreeSwaptionEngine(modelBK, 50)); Console.WriteLine("BK (num): " + bermudanSwaption.NPV()); DateTime endTime = DateTime.Now; TimeSpan delta = endTime - startTime; Console.WriteLine(); Console.WriteLine("Run completed in {0} s", delta.TotalSeconds); Console.WriteLine(); }
void testBootstrapFromUpfront <T, I>() where T : ITraits <DefaultProbabilityTermStructure>, new() where I : class, IInterpolationFactory, new() { Calendar calendar = new TARGET(); Date today = Settings.Instance.evaluationDate(); int settlementDays = 1; List <double> quote = new List <double>(); quote.Add(0.01); quote.Add(0.02); quote.Add(0.04); quote.Add(0.06); List <int> n = new List <int>(); n.Add(2); n.Add(3); n.Add(5); n.Add(7); double fixedRate = 0.05; Frequency frequency = Frequency.Quarterly; BusinessDayConvention convention = BusinessDayConvention.ModifiedFollowing; DateGeneration.Rule rule = DateGeneration.Rule.CDS; DayCounter dayCounter = new Actual360(); double recoveryRate = 0.4; int upfrontSettlementDays = 3; RelinkableHandle <YieldTermStructure> discountCurve = new RelinkableHandle <YieldTermStructure>(); discountCurve.linkTo(new FlatForward(today, 0.06, new Actual360())); List <CdsHelper> helpers = new List <CdsHelper>(); for (int i = 0; i < n.Count; i++) { helpers.Add( new UpfrontCdsHelper(quote[i], fixedRate, new Period(n[i], TimeUnit.Years), settlementDays, calendar, frequency, convention, rule, dayCounter, recoveryRate, discountCurve, upfrontSettlementDays, true, true, null, new Actual360(true))); } RelinkableHandle <DefaultProbabilityTermStructure> piecewiseCurve = new RelinkableHandle <DefaultProbabilityTermStructure>(); piecewiseCurve.linkTo(new PiecewiseDefaultCurve <T, I>(today, helpers, new Thirty360())); double notional = 1.0; double tolerance = 1.0e-6; SavedSettings backup = new SavedSettings(); // ensure apple-to-apple comparison Settings.Instance.includeTodaysCashFlows = true; for (int i = 0; i < n.Count; i++) { Date protectionStart = today + settlementDays; Date startDate = calendar.adjust(protectionStart, convention); Date endDate = today + new Period(n[i], TimeUnit.Years); Date upfrontDate = calendar.advance(today, upfrontSettlementDays, TimeUnit.Days, convention); Schedule schedule = new Schedule(startDate, endDate, new Period(frequency), calendar, convention, BusinessDayConvention.Unadjusted, rule, false); schedule.isRegular().Insert(0, schedule.isRegular()[0]); schedule.dates().Insert(0, protectionStart); CreditDefaultSwap cds = new CreditDefaultSwap(CreditDefaultSwap.Protection.Side.Buyer, notional, quote[i], fixedRate, schedule, convention, dayCounter, true, true, protectionStart, upfrontDate, null, new Actual360(true), true); cds.setPricingEngine(new MidPointCdsEngine(piecewiseCurve, recoveryRate, discountCurve, true)); // test double inputUpfront = quote[i]; double computedUpfront = cds.fairUpfront(); if (Math.Abs(inputUpfront - computedUpfront) > tolerance) { QAssert.Fail( "\nFailed to reproduce fair upfront for " + n[i] + "Y credit-default swaps\n" + " computed: " + computedUpfront.ToString() + "\n" + " expected: " + inputUpfront.ToString()); } } backup.Dispose(); }
static void Main(string[] args) { DateTime timer = DateTime.Now; Date todaysDate = new Date(15, 2, 2002); Calendar calendar = new TARGET(); Date settlementDate = new Date(19, 2, 2002); Settings.setEvaluationDate(todaysDate); // flat yield term structure impling 1x5 swap at 5% Quote flatRate = new SimpleQuote(0.04875825); Handle <YieldTermStructure> rhTermStructure = new Handle <YieldTermStructure>( new FlatForward(settlementDate, new Handle <Quote>(flatRate), new Actual365Fixed())); // Define the ATM/OTM/ITM swaps Frequency fixedLegFrequency = Frequency.Annual; BusinessDayConvention fixedLegConvention = BusinessDayConvention.Unadjusted; BusinessDayConvention floatingLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter fixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.European); Frequency floatingLegFrequency = Frequency.Semiannual; VanillaSwap.Type type = VanillaSwap.Type.Payer; double dummyFixedRate = 0.03; IborIndex indexSixMonths = new Euribor6M(rhTermStructure); Date startDate = calendar.advance(settlementDate, 1, TimeUnit.Years, floatingLegConvention); Date maturity = calendar.advance(startDate, 5, TimeUnit.Years, floatingLegConvention); Schedule fixedSchedule = new Schedule(startDate, maturity, new Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false); Schedule floatSchedule = new Schedule(startDate, maturity, new Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration.Rule.Forward, false); VanillaSwap swap = new VanillaSwap( type, 1000.0, fixedSchedule, dummyFixedRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); swap.setPricingEngine(new DiscountingSwapEngine(rhTermStructure)); double fixedAtmRate = swap.fairRate(); double fixedOtmRate = fixedAtmRate * 1.2; double fixedItmRate = fixedAtmRate * 0.8; VanillaSwap atmSwap = new VanillaSwap( type, 1000.0, fixedSchedule, fixedAtmRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); VanillaSwap otmSwap = new VanillaSwap( type, 1000.0, fixedSchedule, fixedOtmRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); VanillaSwap itmSwap = new VanillaSwap( type, 1000.0, fixedSchedule, fixedItmRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); // defining the swaptions to be used in model calibration List <Period> swaptionMaturities = new List <Period>(5); swaptionMaturities.Add(new Period(1, TimeUnit.Years)); swaptionMaturities.Add(new Period(2, TimeUnit.Years)); swaptionMaturities.Add(new Period(3, TimeUnit.Years)); swaptionMaturities.Add(new Period(4, TimeUnit.Years)); swaptionMaturities.Add(new Period(5, TimeUnit.Years)); List <CalibrationHelper> swaptions = new List <CalibrationHelper>(); // List of times that have to be included in the timegrid List <double> times = new List <double>(); for (int i = 0; i < NumRows; i++) { int j = NumCols - i - 1; // 1x5, 2x4, 3x3, 4x2, 5x1 int k = i * NumCols + j; Quote vol = new SimpleQuote(SwaptionVols[k]); swaptions.Add(new SwaptionHelper(swaptionMaturities[i], new Period(SwapLenghts[j], TimeUnit.Years), new Handle <Quote>(vol), indexSixMonths, indexSixMonths.tenor(), indexSixMonths.dayCounter(), indexSixMonths.dayCounter(), rhTermStructure, false)); swaptions.Last().addTimesTo(times); } // Building time-grid TimeGrid grid = new TimeGrid(times, 30); // defining the models G2 modelG2 = new G2(rhTermStructure); HullWhite modelHw = new HullWhite(rhTermStructure); HullWhite modelHw2 = new HullWhite(rhTermStructure); BlackKarasinski modelBk = new BlackKarasinski(rhTermStructure); // model calibrations Console.WriteLine("G2 (analytic formulae) calibration"); for (int i = 0; i < swaptions.Count; i++) { swaptions[i].setPricingEngine(new G2SwaptionEngine(modelG2, 6.0, 16)); } CalibrateModel(modelG2, swaptions); Console.WriteLine("calibrated to:\n" + "a = {0:0.000000}, " + "sigma = {1:0.0000000}\n" + "b = {2:0.000000}, " + "eta = {3:0.0000000}\n" + "rho = {4:0.00000}\n", modelG2.parameters()[0], modelG2.parameters()[1], modelG2.parameters()[2], modelG2.parameters()[3], modelG2.parameters()[4]); Console.WriteLine("Hull-White (analytic formulae) calibration"); for (int i = 0; i < swaptions.Count; i++) { swaptions[i].setPricingEngine(new JamshidianSwaptionEngine(modelHw)); } CalibrateModel(modelHw, swaptions); Console.WriteLine("calibrated to:\n" + "a = {0:0.000000}, " + "sigma = {1:0.0000000}\n", modelHw.parameters()[0], modelHw.parameters()[1]); Console.WriteLine("Hull-White (numerical) calibration"); for (int i = 0; i < swaptions.Count(); i++) { swaptions[i].setPricingEngine(new TreeSwaptionEngine(modelHw2, grid)); } CalibrateModel(modelHw2, swaptions); Console.WriteLine("calibrated to:\n" + "a = {0:0.000000}, " + "sigma = {1:0.0000000}\n", modelHw2.parameters()[0], modelHw2.parameters()[1]); Console.WriteLine("Black-Karasinski (numerical) calibration"); for (int i = 0; i < swaptions.Count; i++) { swaptions[i].setPricingEngine(new TreeSwaptionEngine(modelBk, grid)); } CalibrateModel(modelBk, swaptions); Console.WriteLine("calibrated to:\n" + "a = {0:0.000000}, " + "sigma = {1:0.00000}\n", modelBk.parameters()[0], modelBk.parameters()[1]); // ATM Bermudan swaption pricing Console.WriteLine("Payer bermudan swaption " + "struck at {0:0.00000 %} (ATM)", fixedAtmRate); List <Date> bermudanDates = new List <Date>(); List <CashFlow> leg = swap.fixedLeg(); for (int i = 0; i < leg.Count; i++) { Coupon coupon = (Coupon)leg[i]; bermudanDates.Add(coupon.accrualStartDate()); } Exercise bermudanExercise = new BermudanExercise(bermudanDates); Swaption bermudanSwaption = new Swaption(atmSwap, bermudanExercise); // Do the pricing for each model // G2 price the European swaption here, it should switch to bermudan bermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelG2, 50)); Console.WriteLine("G2: {0:0.00}", bermudanSwaption.NPV()); bermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw, 50)); Console.WriteLine("HW: {0:0.000}", bermudanSwaption.NPV()); bermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw2, 50)); Console.WriteLine("HW (num): {0:0.000}", bermudanSwaption.NPV()); bermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelBk, 50)); Console.WriteLine("BK: {0:0.000}", bermudanSwaption.NPV()); // OTM Bermudan swaption pricing Console.WriteLine("Payer bermudan swaption " + "struck at {0:0.00000 %} (OTM)", fixedOtmRate); Swaption otmBermudanSwaption = new Swaption(otmSwap, bermudanExercise); // Do the pricing for each model otmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelG2, 50)); Console.WriteLine("G2: {0:0.0000}", otmBermudanSwaption.NPV()); otmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw, 50)); Console.WriteLine("HW: {0:0.0000}", otmBermudanSwaption.NPV()); otmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw2, 50)); Console.WriteLine("HW (num): {0:0.000}", otmBermudanSwaption.NPV()); otmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelBk, 50)); Console.WriteLine("BK: {0:0.0000}", otmBermudanSwaption.NPV()); // ITM Bermudan swaption pricing Console.WriteLine("Payer bermudan swaption " + "struck at {0:0.00000 %} (ITM)", fixedItmRate); Swaption itmBermudanSwaption = new Swaption(itmSwap, bermudanExercise); // Do the pricing for each model itmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelG2, 50)); Console.WriteLine("G2: {0:0.000}", itmBermudanSwaption.NPV()); itmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw, 50)); Console.WriteLine("HW: {0:0.000}", itmBermudanSwaption.NPV()); itmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw2, 50)); Console.WriteLine("HW (num): {0:0.000}", itmBermudanSwaption.NPV()); itmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelBk, 50)); Console.WriteLine("BK: {0:0.000}", itmBermudanSwaption.NPV()); Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.WriteLine(); Console.Write("Press any key to continue ..."); Console.ReadKey(); }
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(); } }
static void Main(string[] args) { DateTime timer = DateTime.Now; /********************* *** MARKET DATA *** *********************/ Calendar calendar = new TARGET(); Date settlementDate = new Date(22, Month.September, 2004); // must be a business day settlementDate = calendar.adjust(settlementDate); int fixingDays = 2; Date todaysDate = calendar.advance(settlementDate, -fixingDays, TimeUnit.Days); // nothing to do with Date::todaysDate Settings.setEvaluationDate(todaysDate); todaysDate = Settings.evaluationDate(); Console.WriteLine("Today: {0}, {1}", todaysDate.DayOfWeek, todaysDate); Console.WriteLine("Settlement date: {0}, {1}", settlementDate.DayOfWeek, settlementDate); // deposits double d1wQuote = 0.0382; double d1mQuote = 0.0372; double d3mQuote = 0.0363; double d6mQuote = 0.0353; double d9mQuote = 0.0348; double d1yQuote = 0.0345; // FRAs double fra3x6Quote = 0.037125; double fra6x9Quote = 0.037125; double fra6x12Quote = 0.037125; // futures double fut1Quote = 96.2875; double fut2Quote = 96.7875; double fut3Quote = 96.9875; double fut4Quote = 96.6875; double fut5Quote = 96.4875; double fut6Quote = 96.3875; double fut7Quote = 96.2875; double fut8Quote = 96.0875; // swaps double s2yQuote = 0.037125; double s3yQuote = 0.0398; double s5yQuote = 0.0443; double s10yQuote = 0.05165; double s15yQuote = 0.055175; /******************** *** 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); // FRAs Quote fra3x6Rate = new SimpleQuote(fra3x6Quote); Quote fra6x9Rate = new SimpleQuote(fra6x9Quote); Quote fra6x12Rate = new SimpleQuote(fra6x12Quote); // futures Quote fut1Price = new SimpleQuote(fut1Quote); Quote fut2Price = new SimpleQuote(fut2Quote); Quote fut3Price = new SimpleQuote(fut3Quote); Quote fut4Price = new SimpleQuote(fut4Quote); Quote fut5Price = new SimpleQuote(fut5Quote); Quote fut6Price = new SimpleQuote(fut6Quote); Quote fut7Price = new SimpleQuote(fut7Quote); Quote fut8Price = new SimpleQuote(fut8Quote); // 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 FRAs RateHelper fra3x6 = new FraRateHelper(new Handle <Quote>(fra3x6Rate), 3, 6, fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper fra6x9 = new FraRateHelper(new Handle <Quote>(fra6x9Rate), 6, 9, fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper fra6x12 = new FraRateHelper(new Handle <Quote>(fra6x12Rate), 6, 12, fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); // setup futures // Handle<Quote> convexityAdjustment = new Handle<Quote>(new SimpleQuote(0.0)); int futMonths = 3; Date imm = IMM.nextDate(settlementDate); RateHelper fut1 = new FuturesRateHelper(new Handle <Quote>(fut1Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut2 = new FuturesRateHelper(new Handle <Quote>(fut2Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut3 = new FuturesRateHelper(new Handle <Quote>(fut3Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut4 = new FuturesRateHelper(new Handle <Quote>(fut4Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut5 = new FuturesRateHelper(new Handle <Quote>(fut5Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut6 = new FuturesRateHelper(new Handle <Quote>(fut6Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut7 = new FuturesRateHelper(new Handle <Quote>(fut7Price), imm, futMonths, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); imm = IMM.nextDate(imm + 1); RateHelper fut8 = new FuturesRateHelper(new Handle <Quote>(fut8Price), imm, futMonths, 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(); RateHelper s2y = new SwapRateHelper(new Handle <Quote>(s2yRate), new Period(2, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); RateHelper s3y = new SwapRateHelper(new Handle <Quote>(s3yRate), new Period(3, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); RateHelper s5y = new SwapRateHelper(new Handle <Quote>(s5yRate), new Period(5, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); RateHelper s10y = new SwapRateHelper(new Handle <Quote>(s10yRate), new Period(10, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); RateHelper s15y = new SwapRateHelper(new Handle <Quote>(s15yRate), new Period(15, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex); /********************* ** 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-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); // A depo-futures-swap curve List <RateHelper> depoFutSwapInstruments = new List <RateHelper>(); depoFutSwapInstruments.Add(d1w); depoFutSwapInstruments.Add(d1m); depoFutSwapInstruments.Add(fut1); depoFutSwapInstruments.Add(fut2); depoFutSwapInstruments.Add(fut3); depoFutSwapInstruments.Add(fut4); depoFutSwapInstruments.Add(fut5); depoFutSwapInstruments.Add(fut6); depoFutSwapInstruments.Add(fut7); depoFutSwapInstruments.Add(fut8); depoFutSwapInstruments.Add(s3y); depoFutSwapInstruments.Add(s5y); depoFutSwapInstruments.Add(s10y); depoFutSwapInstruments.Add(s15y); YieldTermStructure depoFutSwapTermStructure = new PiecewiseYieldCurve <Discount, LogLinear>( settlementDate, depoFutSwapInstruments, termStructureDayCounter, new List <Handle <Quote> >(), new List <Date>(), tolerance); // A depo-FRA-swap curve List <RateHelper> depoFRASwapInstruments = new List <RateHelper>(); depoFRASwapInstruments.Add(d1w); depoFRASwapInstruments.Add(d1m); depoFRASwapInstruments.Add(d3m); depoFRASwapInstruments.Add(fra3x6); depoFRASwapInstruments.Add(fra6x9); depoFRASwapInstruments.Add(fra6x12); depoFRASwapInstruments.Add(s2y); depoFRASwapInstruments.Add(s3y); depoFRASwapInstruments.Add(s5y); depoFRASwapInstruments.Add(s10y); depoFRASwapInstruments.Add(s15y); YieldTermStructure depoFRASwapTermStructure = new PiecewiseYieldCurve <Discount, LogLinear>( settlementDate, depoFRASwapInstruments, 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>(); /********************* * SWAPS TO BE PRICED * **********************/ // constant nominal 1,000,000 Euro double nominal = 1000000.0; // fixed leg Frequency fixedLegFrequency = Frequency.Annual; BusinessDayConvention fixedLegConvention = BusinessDayConvention.Unadjusted; BusinessDayConvention floatingLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter fixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.European); double fixedRate = 0.04; DayCounter floatingLegDayCounter = new Actual360(); // floating leg Frequency floatingLegFrequency = Frequency.Semiannual; IborIndex euriborIndex = new Euribor6M(forecastingTermStructure); double spread = 0.0; int lenghtInYears = 5; VanillaSwap.Type swapType = VanillaSwap.Type.Payer; Date maturity = settlementDate + new Period(lenghtInYears, TimeUnit.Years); Schedule fixedSchedule = new Schedule(settlementDate, maturity, new Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false); Schedule floatSchedule = new Schedule(settlementDate, maturity, new Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration.Rule.Forward, false); VanillaSwap spot5YearSwap = new VanillaSwap(swapType, nominal, fixedSchedule, fixedRate, fixedLegDayCounter, floatSchedule, euriborIndex, spread, floatingLegDayCounter); Date fwdStart = calendar.advance(settlementDate, 1, TimeUnit.Years); Date fwdMaturity = fwdStart + new Period(lenghtInYears, TimeUnit.Years); Schedule fwdFixedSchedule = new Schedule(fwdStart, fwdMaturity, new Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false); Schedule fwdFloatSchedule = new Schedule(fwdStart, fwdMaturity, new Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration.Rule.Forward, false); VanillaSwap oneYearForward5YearSwap = new VanillaSwap(swapType, nominal, fwdFixedSchedule, fixedRate, fixedLegDayCounter, fwdFloatSchedule, euriborIndex, spread, floatingLegDayCounter); /*************** * SWAP PRICING * ****************/ // utilities for reporting List <string> headers = new List <string>(); headers.Add("term structure"); headers.Add("net present value"); headers.Add("fair spread"); headers.Add("fair fixed rate"); string separator = " | "; int width = headers[0].Length + separator.Length + headers[1].Length + separator.Length + headers[2].Length + separator.Length + headers[3].Length + separator.Length - 1; string rule = string.Format("").PadLeft(width, '-'), dblrule = string.Format("").PadLeft(width, '='); string tab = string.Format("").PadLeft(8, ' '); // calculations Console.WriteLine(dblrule); Console.WriteLine("5-year market swap-rate = {0:0.00%}", s5yRate.value()); Console.WriteLine(dblrule); Console.WriteLine(tab + "5-years swap paying {0:0.00%}", fixedRate); Console.WriteLine(headers[0] + separator + headers[1] + separator + headers[2] + separator + headers[3] + separator); Console.WriteLine(rule); double NPV; double fairRate; double fairSpread; IPricingEngine swapEngine = new DiscountingSwapEngine(discountingTermStructure); spot5YearSwap.setPricingEngine(swapEngine); oneYearForward5YearSwap.setPricingEngine(swapEngine); // Of course, you're not forced to really use different curves forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); // let's check that the 5 years swap has been correctly re-priced if (!(Math.Abs(fairRate - s5yQuote) < 1e-8)) { throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate - s5yQuote)); } forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-fut-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate - s5yQuote) < 1e-8)) { throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate - s5yQuote)); } forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-FRA-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate - s5yQuote) < 1e-8)) { throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate - s5yQuote)); } Console.WriteLine(rule); // now let's price the 1Y forward 5Y swap Console.WriteLine(tab + "5-years, 1-year forward swap paying {0:0.00%}", fixedRate); Console.WriteLine(headers[0] + separator + headers[1] + separator + headers[2] + separator + headers[3] + separator); Console.WriteLine(rule); forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-fut-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-FRA-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); // now let's say that the 5-years swap rate goes up to 4.60%. // A smarter market element--say, connected to a data source-- would // notice the change itself. Since we're using SimpleQuotes, // we'll have to change the value manually--which forces us to // downcast the handle and use the SimpleQuote // interface. In any case, the point here is that a change in the // value contained in the Quote triggers a new bootstrapping // of the curve and a repricing of the swap. SimpleQuote fiveYearsRate = s5yRate as SimpleQuote; fiveYearsRate.setValue(0.0460); Console.WriteLine(dblrule); Console.WriteLine("5-year market swap-rate = {0:0.00%}", s5yRate.value()); Console.WriteLine(dblrule); Console.WriteLine(tab + "5-years swap paying {0:0.00%}", fixedRate); Console.WriteLine(headers[0] + separator + headers[1] + separator + headers[2] + separator + headers[3] + separator); Console.WriteLine(rule); // now get the updated results forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate - s5yRate.value()) < 1e-8)) { throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate - s5yRate.value())); } forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-fut-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate - s5yRate.value()) < 1e-8)) { throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate - s5yRate.value())); } forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-FRA-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); if (!(Math.Abs(fairRate - s5yRate.value()) < 1e-8)) { throw new ApplicationException("5-years swap mispriced by " + Math.Abs(fairRate - s5yRate.value())); } Console.WriteLine(rule); // the 1Y forward 5Y swap changes as well Console.WriteLine(tab + "5-years, 1-year forward swap paying {0:0.00%}", fixedRate); Console.WriteLine(headers[0] + separator + headers[1] + separator + headers[2] + separator + headers[3] + separator); Console.WriteLine(rule); forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-fut-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); Console.Write("{0," + headers[0].Length + ":0.00}" + separator, "depo-FRA-swap"); Console.Write("{0," + headers[1].Length + ":0.00}" + separator, NPV); Console.Write("{0," + headers[2].Length + ":0.00%}" + separator, fairSpread); Console.WriteLine("{0," + headers[3].Length + ":0.00%}" + separator, fairRate); Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.Write("Press any key to continue ..."); Console.ReadKey(); }
static void Main(string[] args) { /* * TODO: * FIXES * 1. WAC vs Net Coupon (meanings are reversed, names are bad) * 2. CashFlows needs to be replaced with Expected CashFlows to get the correct price * NEW IMPLEMENTATION * 1. Add delay * 2. Add SecType enum PT, PO, IO */ Date referenceDate = new Date(16, 11, 2015); Settings.setEvaluationDate(referenceDate); int settlementDays = 0; Calendar calendar = new TARGET(); int origTerm = 360; Frequency sinkingFrequency = Frequency.Monthly; DayCounter accrualDayCounter = new Thirty360(); BusinessDayConvention paymentConvention = BusinessDayConvention.Unadjusted; double wac = 0.03875; int wam = 357; int wala = origTerm - wam; Date factorDate = new Date(1, 12, 2015); Date issueDate = calendar.advance(factorDate, -wala, TimeUnit.Months, BusinessDayConvention.Unadjusted); double factor = 1.0; double currentFace = 1000000; double originalFace = currentFace / factor; int statedDelay = 30; //54; double netCoupon = 0.030; string secType = "PT"; Date settleDate = referenceDate; double yield_be = 0.0270; //double price; double speed = 0.08; IPrepayModel prepaymodel = new ConstantCPR(speed); //IPrepayModel prepaymodel = new PSACurve(factorDate, speed); MBSFixedRateBond mbs = new MBSFixedRateBond( settlementDays, calendar, currentFace, factorDate, new Period(wam, TimeUnit.Months), new Period(origTerm, TimeUnit.Months), sinkingFrequency, wac, netCoupon, accrualDayCounter, prepaymodel, paymentConvention, issueDate); YieldTermStructure discountCurve = new FlatForward(referenceDate, yield_be, new Thirty360(), Compounding.Compounded, Frequency.Semiannual); DiscountingBondEngine discountingBondEngine = new DiscountingBondEngine(new Handle <YieldTermStructure>(discountCurve)); mbs.setPricingEngine(discountingBondEngine); // display results Console.WriteLine("WAC : {0:F5}", wac); Console.WriteLine("WALA : {0}", wala); Console.WriteLine("WAM : {0}", wam); Console.WriteLine("Factor Date : {0}", factorDate.ToShortDateString()); Console.WriteLine("Factor : {0:F10}", factor); Console.WriteLine("Orig Face : {0:N}", originalFace); Console.WriteLine("Curr Face : {0:N}", currentFace); Console.WriteLine("Stated Delay: {0}", statedDelay); Console.WriteLine("Net Coupon : {0:F3}", netCoupon); Console.WriteLine("Sec Type : {0}", secType); Console.WriteLine("Settle Date : {0}", settleDate.ToShortDateString()); Console.WriteLine("Model Type : {0}", prepaymodel.GetType().ToString()); Console.WriteLine("Model Speed : {0:F3}", speed); Console.WriteLine("Yield : {0:F5}", yield_be); Console.WriteLine("Clean Price : {0:F6}", mbs.cleanPrice()); Console.WriteLine("Dirty Price : {0:F6}", mbs.dirtyPrice()); Console.WriteLine("Accrued : {0:F6}", mbs.accruedAmount()); // month, factor, pay date, ending prin, interest, reg principal, prepaid principal, total principal, net flow, cpr, smm, wala, wam, p&i payment, i payment, beg balance, days, discount, pv double ebal = currentFace; using (System.IO.StreamWriter sw = new System.IO.StreamWriter("output.csv")) { DayCounter dc = discountCurve.dayCounter(); Date refdate = discountCurve.referenceDate(); sw.WriteLine("month,factor date,factor,pay date,ending principal,interest,regular principal,prepaid principal,total principal,net flow,cpr,smm,wala,wam,p&i payment,interest payment,beginning balance,days,discount,pv"); for (int i = 0; i < wam; i++) { double upmt = 0; double ppmt = 0; double ipmt = 0; double bbal = ebal; Date paydate = null; for (int j = 0; j <= 2; j++) { int k = i * 3 + j; CashFlow cf = mbs.expectedCashflows()[k]; if (cf.GetType() == typeof(VoluntaryPrepay)) { upmt = cf.amount(); paydate = cf.date(); } if (cf.GetType() == typeof(AmortizingPayment)) { ppmt = cf.amount(); } if (cf.GetType() == typeof(FixedRateCoupon)) { ipmt = cf.amount(); } } int days = dc.dayCount(refdate, paydate); double df = discountCurve.discount(paydate); ebal = bbal - upmt - ppmt; double smm = upmt / (bbal - ppmt); sw.Write("{0},", i + 1); //month sw.Write("{0},", calendar.advance(factorDate, i, TimeUnit.Months, BusinessDayConvention.Unadjusted)); //factor date sw.Write("{0:F10},", factor * bbal / currentFace); //factor sw.Write("{0},", paydate.ToShortDateString()); //pay date sw.Write("{0:F2},", ebal); //ending principal sw.Write("{0:F2},", ipmt); //interest sw.Write("{0:F2},", ppmt); //regular principal sw.Write("{0:F2},", upmt); //prepaid principal sw.Write("{0:F2},", ppmt + upmt); //total principal sw.Write("{0:F2},", ipmt + ppmt + upmt); //net flow sw.Write("{0:F4},", 1 - Math.Pow(1 - smm, 12)); //cpr sw.Write("{0:F6},", smm); //smm sw.Write("{0},", wala + i); //wala sw.Write("{0},", wam - i); //wam sw.Write("{0},", i); //p&i payment sw.Write("{0},", i); //interest payment sw.Write("{0:F2},", bbal); //beginning balance sw.Write("{0},", days); //days sw.Write("{0:F8},", df); //discount sw.WriteLine("{0}", df * (ipmt + ppmt + upmt)); //pv } } }
static void Main(string[] args) { try { Option.Type type = Option.Type.Put; double underlying = 36.0; double spreadRate = 0.005; double dividendYield = 0.02; double riskFreeRate = 0.06; double volatility = 0.2; int settlementDays = 3; int length = 5; double redemption = 100.0; double conversionRatio = redemption / underlying; // at the money // set up dates/schedules Calendar calendar = new TARGET(); Date today = calendar.adjust(Date.Today); Settings.setEvaluationDate(today); Date settlementDate = calendar.advance(today, settlementDays, TimeUnit.Days); Date exerciseDate = calendar.advance(settlementDate, length, TimeUnit.Years); Date issueDate = calendar.advance(exerciseDate, -length, TimeUnit.Years); BusinessDayConvention convention = BusinessDayConvention.ModifiedFollowing; Frequency frequency = Frequency.Annual; Schedule schedule = new Schedule(issueDate, exerciseDate, new Period(frequency), calendar, convention, convention, DateGeneration.Rule.Backward, false); DividendSchedule dividends = new DividendSchedule(); CallabilitySchedule callability = new CallabilitySchedule(); List <double> coupons = new InitializedList <double>(1, 0.05); DayCounter bondDayCount = new Thirty360(); int[] callLength = { 2, 4 }; // Call dates, years 2,4. int[] putLength = { 3 }; // Put dates year 3. double[] callPrices = { 101.5, 100.85 }; double[] putPrices = { 105.0 }; // Load call schedules for (int i = 0; i < callLength.Length; i++) { SoftCallability s = new SoftCallability( new Callability.Price(callPrices[i], Callability.Price.Type.Clean), schedule.date(callLength[i]), 1.20); callability.Add(s); } for (int j = 0; j < putLength.Length; j++) { Callability s = new Callability(new Callability.Price(putPrices[j], Callability.Price.Type.Clean), Callability.Type.Put, schedule.date(putLength[j])); callability.Add(s); } // Assume dividends are paid every 6 months . for (Date d = today + new Period(6, TimeUnit.Months); d < exerciseDate; d += new Period(6, TimeUnit.Months)) { Dividend div = new FixedDividend(1.0, d); dividends.Add(div); } DayCounter dayCounter = new Actual365Fixed(); double maturity = dayCounter.yearFraction(settlementDate, exerciseDate); Console.WriteLine("option type = " + type); Console.WriteLine("Time to maturity = " + maturity); Console.WriteLine("Underlying price = " + underlying); Console.WriteLine("Risk-free interest rate = {0:0.0%}", riskFreeRate); Console.WriteLine("Dividend yield = {0:0.0%}%", dividendYield); Console.WriteLine("Volatility = {0:0.0%}%", volatility); Console.WriteLine(""); // write column headings int[] widths = { 35, 14, 14 }; int totalWidth = widths[0] + widths[1] + widths[2]; string rule = new string('-', totalWidth); string dblrule = new string('=', totalWidth); Console.WriteLine(dblrule); Console.WriteLine("Tsiveriotis-Fernandes method"); Console.WriteLine(dblrule); Console.WriteLine("Tree Type European American "); Console.WriteLine(rule); Exercise exercise = new EuropeanExercise(exerciseDate); Exercise amexercise = new AmericanExercise(settlementDate, exerciseDate); Handle <Quote> underlyingH = new Handle <Quote>(new SimpleQuote(underlying)); Handle <YieldTermStructure> flatTermStructure = new Handle <YieldTermStructure>(new FlatForward(settlementDate, riskFreeRate, dayCounter)); Handle <YieldTermStructure> flatDividendTS = new Handle <YieldTermStructure>(new FlatForward(settlementDate, dividendYield, dayCounter)); Handle <BlackVolTermStructure> flatVolTS = new Handle <BlackVolTermStructure>(new BlackConstantVol(settlementDate, calendar, volatility, dayCounter)); BlackScholesMertonProcess stochasticProcess = new BlackScholesMertonProcess(underlyingH, flatDividendTS, flatTermStructure, flatVolTS); int timeSteps = 801; Handle <Quote> creditSpread = new Handle <Quote>(new SimpleQuote(spreadRate)); Quote rate = new SimpleQuote(riskFreeRate); Handle <YieldTermStructure> discountCurve = new Handle <YieldTermStructure>(new FlatForward(today, new Handle <Quote>(rate), dayCounter)); IPricingEngine engine = new BinomialConvertibleEngine <JarrowRudd>(stochasticProcess, timeSteps); ConvertibleFixedCouponBond europeanBond = new ConvertibleFixedCouponBond(exercise, conversionRatio, dividends, callability, creditSpread, issueDate, settlementDays, coupons, bondDayCount, schedule, redemption); europeanBond.setPricingEngine(engine); ConvertibleFixedCouponBond americanBond = new ConvertibleFixedCouponBond(amexercise, conversionRatio, dividends, callability, creditSpread, issueDate, settlementDays, coupons, bondDayCount, schedule, redemption); americanBond.setPricingEngine(engine); Console.WriteLine("Jarrow-Rudd {0:0.000000} {1:0.000000}", europeanBond.NPV(), americanBond.NPV()); americanBond.setPricingEngine(new BinomialConvertibleEngine <CoxRossRubinstein>(stochasticProcess, timeSteps)); europeanBond.setPricingEngine(new BinomialConvertibleEngine <CoxRossRubinstein>(stochasticProcess, timeSteps)); Console.WriteLine("CoxRossRubinstein {0:0.000000} {1:0.000000}", europeanBond.NPV(), americanBond.NPV()); americanBond.setPricingEngine(new BinomialConvertibleEngine <AdditiveEQPBinomialTree>(stochasticProcess, timeSteps)); europeanBond.setPricingEngine(new BinomialConvertibleEngine <AdditiveEQPBinomialTree>(stochasticProcess, timeSteps)); Console.WriteLine("AdditiveEQPBinomialTree {0:0.000000} {1:0.000000}", europeanBond.NPV(), americanBond.NPV()); americanBond.setPricingEngine(new BinomialConvertibleEngine <Trigeorgis>(stochasticProcess, timeSteps)); europeanBond.setPricingEngine(new BinomialConvertibleEngine <Trigeorgis>(stochasticProcess, timeSteps)); Console.WriteLine("Trigeorgis {0:0.000000} {1:0.000000}", europeanBond.NPV(), americanBond.NPV()); americanBond.setPricingEngine(new BinomialConvertibleEngine <Tian>(stochasticProcess, timeSteps)); europeanBond.setPricingEngine(new BinomialConvertibleEngine <Tian>(stochasticProcess, timeSteps)); Console.WriteLine("Tian {0:0.000000} {1:0.000000}", europeanBond.NPV(), americanBond.NPV()); americanBond.setPricingEngine(new BinomialConvertibleEngine <LeisenReimer>(stochasticProcess, timeSteps)); europeanBond.setPricingEngine(new BinomialConvertibleEngine <LeisenReimer>(stochasticProcess, timeSteps)); Console.WriteLine("LeisenReimer {0:0.000000} {1:0.000000}", europeanBond.NPV(), americanBond.NPV()); americanBond.setPricingEngine(new BinomialConvertibleEngine <Joshi4>(stochasticProcess, timeSteps)); europeanBond.setPricingEngine(new BinomialConvertibleEngine <Joshi4>(stochasticProcess, timeSteps)); Console.WriteLine("Joshi4 {0:0.000000} {1:0.000000}", europeanBond.NPV(), americanBond.NPV()); Console.WriteLine("==========================================================================="); } catch (Exception e) { Console.WriteLine(e.ToString()); } Console.ReadKey(); }
public void testCachedValue() { // Testing credit-default swap against cached values... using (SavedSettings backup = new SavedSettings()) { // Initialize curves Settings.setEvaluationDate(new Date(9, Month.June, 2006)); Date today = Settings.evaluationDate(); Calendar calendar = new TARGET(); Handle <Quote> hazardRate = new Handle <Quote>(new SimpleQuote(0.01234)); RelinkableHandle <DefaultProbabilityTermStructure> probabilityCurve = new RelinkableHandle <DefaultProbabilityTermStructure>(); probabilityCurve.linkTo(new FlatHazardRate(0, calendar, hazardRate, new Actual360())); RelinkableHandle <YieldTermStructure> discountCurve = new RelinkableHandle <YieldTermStructure>(); discountCurve.linkTo(new FlatForward(today, 0.06, new Actual360())); // Build the schedule Date issueDate = calendar.advance(today, -1, TimeUnit.Years); Date maturity = calendar.advance(issueDate, 10, TimeUnit.Years); Frequency frequency = Frequency.Semiannual; BusinessDayConvention convention = BusinessDayConvention.ModifiedFollowing; Schedule schedule = new Schedule(issueDate, maturity, new Period(frequency), calendar, convention, convention, DateGeneration.Rule.Forward, false); // Build the CDS double fixedRate = 0.0120; DayCounter dayCount = new Actual360(); double notional = 10000.0; double recoveryRate = 0.4; CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, notional, fixedRate, schedule, convention, dayCount, true, true); cds.setPricingEngine(new MidPointCdsEngine(probabilityCurve, recoveryRate, discountCurve)); double npv = 295.0153398; double fairRate = 0.007517539081; double calculatedNpv = cds.NPV(); double calculatedFairRate = cds.fairSpread(); double tolerance = 1.0e-7; if (Math.Abs(calculatedNpv - npv) > tolerance) { Assert.Fail( "Failed to reproduce NPV with mid-point engine\n" + " calculated NPV: " + calculatedNpv + "\n" + " expected NPV: " + npv); } if (Math.Abs(calculatedFairRate - fairRate) > tolerance) { Assert.Fail( "Failed to reproduce fair rate with mid-point engine\n" + " calculated fair rate: " + calculatedFairRate + "\n" + " expected fair rate: " + fairRate); } cds.setPricingEngine(new IntegralCdsEngine(new Period(1, TimeUnit.Days), probabilityCurve, recoveryRate, discountCurve)); calculatedNpv = cds.NPV(); calculatedFairRate = cds.fairSpread(); tolerance = 1.0e-5; if (Math.Abs(calculatedNpv - npv) > notional * tolerance * 10) { Assert.Fail( "Failed to reproduce NPV with integral engine " + "(step = 1 day)\n" + " calculated NPV: " + calculatedNpv + "\n" + " expected NPV: " + npv); } if (Math.Abs(calculatedFairRate - fairRate) > tolerance) { Assert.Fail( "Failed to reproduce fair rate with integral engine " + "(step = 1 day)\n" + " calculated fair rate: " + calculatedFairRate + "\n" + " expected fair rate: " + fairRate); } cds.setPricingEngine(new IntegralCdsEngine(new Period(1, TimeUnit.Weeks), probabilityCurve, recoveryRate, discountCurve)); calculatedNpv = cds.NPV(); calculatedFairRate = cds.fairSpread(); tolerance = 1.0e-5; if (Math.Abs(calculatedNpv - npv) > notional * tolerance * 10) { Assert.Fail( "Failed to reproduce NPV with integral engine " + "(step = 1 week)\n" + " calculated NPV: " + calculatedNpv + "\n" + " expected NPV: " + npv); } if (Math.Abs(calculatedFairRate - fairRate) > tolerance) { Assert.Fail( "Failed to reproduce fair rate with integral engine " + "(step = 1 week)\n" + " calculated fair rate: " + calculatedFairRate + "\n" + " expected fair rate: " + fairRate); } } }
public void testFairUpfront() { // Testing fair-upfront calculation for credit-default swaps... using (SavedSettings backup = new SavedSettings()) { // Initialize curves Calendar calendar = new TARGET(); Date today = calendar.adjust(Date.Today); Settings.setEvaluationDate(today); Handle <Quote> hazardRate = new Handle <Quote>(new SimpleQuote(0.01234)); RelinkableHandle <DefaultProbabilityTermStructure> probabilityCurve = new RelinkableHandle <DefaultProbabilityTermStructure>(); probabilityCurve.linkTo(new FlatHazardRate(0, calendar, hazardRate, new Actual360())); RelinkableHandle <YieldTermStructure> discountCurve = new RelinkableHandle <YieldTermStructure>(); discountCurve.linkTo(new FlatForward(today, 0.06, new Actual360())); // Build the schedule Date issueDate = today; Date maturity = calendar.advance(issueDate, 10, TimeUnit.Years); BusinessDayConvention convention = BusinessDayConvention.Following; Schedule schedule = new MakeSchedule().from(issueDate) .to(maturity) .withFrequency(Frequency.Quarterly) .withCalendar(calendar) .withTerminationDateConvention(convention) .withRule(DateGeneration.Rule.TwentiethIMM).value(); // Build the CDS double fixedRate = 0.05; double upfront = 0.001; DayCounter dayCount = new Actual360(); double notional = 10000.0; double recoveryRate = 0.4; IPricingEngine engine = new MidPointCdsEngine(probabilityCurve, recoveryRate, discountCurve, true); CreditDefaultSwap cds = new CreditDefaultSwap(Protection.Side.Seller, notional, upfront, fixedRate, schedule, convention, dayCount, true, true); cds.setPricingEngine(engine); double fairUpfront = cds.fairUpfront(); CreditDefaultSwap fairCds = new CreditDefaultSwap(Protection.Side.Seller, notional, fairUpfront, fixedRate, schedule, convention, dayCount, true, true); fairCds.setPricingEngine(engine); double fairNPV = fairCds.NPV(); double tolerance = 1e-10; if (Math.Abs(fairNPV) > tolerance) { Assert.Fail( "Failed to reproduce null NPV with calculated fair upfront\n" + " calculated upfront: " + fairUpfront + "\n" + " calculated NPV: " + fairNPV); } // same with null upfront to begin with upfront = 0.0; CreditDefaultSwap cds2 = new CreditDefaultSwap(Protection.Side.Seller, notional, upfront, fixedRate, schedule, convention, dayCount, true, true); cds2.setPricingEngine(engine); fairUpfront = cds2.fairUpfront(); CreditDefaultSwap fairCds2 = new CreditDefaultSwap(Protection.Side.Seller, notional, fairUpfront, fixedRate, schedule, convention, dayCount, true, true); fairCds2.setPricingEngine(engine); fairNPV = fairCds2.NPV(); if (Math.Abs(fairNPV) > tolerance) { Assert.Fail( "Failed to reproduce null NPV with calculated fair upfront\n" + " calculated upfront: " + fairUpfront + "\n" + " calculated NPV: " + fairNPV); } } }
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) { 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(); }
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); }