[InlineData(false, Frequency.Quarterly, "1999-05-31", "2000-04-30", "1999-08-31", "1999-11-30", "1999-11-30", "2000-04-30", (91.0 / (91.0 * 4)) + (61.0 / (90.0 * 4)))] // example e: long final calculation period - not end of month public void testActualActualIsma(bool isEndOfMonth, Frequency frequency, string interestAccrualDateAsString, string maturityDateAsString, string firstCouponDateAsString, string penultimateCouponDateAsString, string d1AsString, string d2AsString, double expectedYearFraction) { // Example from ISDA Paper: The actual/actual day count fraction, paper for use with the ISDA Market Conventions Survey, 3rd June, 1999 var interestAccrualDate = new Date(DateTime.ParseExact(interestAccrualDateAsString, "yyyy-MM-dd", CultureInfo.InvariantCulture)); var maturityDate = new Date(DateTime.ParseExact(maturityDateAsString, "yyyy-MM-dd", CultureInfo.InvariantCulture)); var firstCouponDate = new Date(DateTime.ParseExact(firstCouponDateAsString, "yyyy-MM-dd", CultureInfo.InvariantCulture)); var penultimateCouponDate = new Date(DateTime.ParseExact(penultimateCouponDateAsString, "yyyy-MM-dd", CultureInfo.InvariantCulture)); var d1 = new Date(DateTime.ParseExact(d1AsString, "yyyy-MM-dd", CultureInfo.InvariantCulture)); var d2 = new Date(DateTime.ParseExact(d2AsString, "yyyy-MM-dd", CultureInfo.InvariantCulture)); var schedule = new MakeSchedule() .from(interestAccrualDate) .to(maturityDate) .withFrequency(frequency) .withFirstDate(firstCouponDate) .withNextToLastDate(penultimateCouponDate) .endOfMonth(isEndOfMonth) .value(); var dayCounter = new ActualActual(ActualActual.Convention.ISMA, schedule); var t = dayCounter.yearFraction(d1, d2); Assert.Equal(expectedYearFraction, t); }
public void zciisconsistency() { CommonVars common = new CommonVars(); ZeroCouponInflationSwap.Type ztype = ZeroCouponInflationSwap.Type.Payer; double nominal = 1000000.0; Date startDate = new Date(common.evaluationDate); Date endDate = new Date(25, Month.November, 2059); Calendar cal = new UnitedKingdom(); BusinessDayConvention paymentConvention = BusinessDayConvention.ModifiedFollowing; DayCounter dummyDC = null, dc = new ActualActual(); Period observationLag = new Period(2, TimeUnit.Months); double quote = 0.03714; ZeroCouponInflationSwap zciis = new ZeroCouponInflationSwap(ztype, nominal, startDate, endDate, cal, paymentConvention, dc, quote, common.ii, observationLag); // simple structure so simple pricing engine - most work done by index DiscountingSwapEngine dse = new DiscountingSwapEngine(common.nominalUK); zciis.setPricingEngine(dse); QAssert.IsTrue(Math.Abs(zciis.NPV()) < 1e-3, "zciis does not reprice to zero"); List <Date> oneDate = new List <Date>(); oneDate.Add(endDate); Schedule schOneDate = new Schedule(oneDate, cal, paymentConvention); CPISwap.Type stype = CPISwap.Type.Payer; double inflationNominal = nominal; double floatNominal = inflationNominal * Math.Pow(1.0 + quote, 50); bool subtractInflationNominal = true; double dummySpread = 0.0, dummyFixedRate = 0.0; int fixingDays = 0; Date baseDate = startDate - observationLag; double baseCPI = common.ii.fixing(baseDate); IborIndex dummyFloatIndex = new IborIndex(); CPISwap cS = new CPISwap(stype, floatNominal, subtractInflationNominal, dummySpread, dummyDC, schOneDate, paymentConvention, fixingDays, dummyFloatIndex, dummyFixedRate, baseCPI, dummyDC, schOneDate, paymentConvention, observationLag, common.ii, InterpolationType.AsIndex, inflationNominal); cS.setPricingEngine(dse); QAssert.IsTrue(Math.Abs(cS.NPV()) < 1e-3, "CPISwap as ZCIIS does not reprice to zero"); for (int i = 0; i < 2; i++) { double cs = cS.legNPV(i).GetValueOrDefault(); double z = zciis.legNPV(i).GetValueOrDefault(); QAssert.IsTrue(Math.Abs(cs - z) < 1e-3, "zciis leg does not equal CPISwap leg"); } // remove circular refernce common.hcpi.linkTo(null); }
public void testForwardRateDayCounter() { CommonVars vars = new CommonVars(); DayCounter d = new ActualActual(); DayCounter d1 = new Actual360(); vars.termStructure = new PiecewiseYieldCurve <Discount, LogLinear>(vars.settlementDays, vars.calendar, vars.instruments, d); InterestRate ir = vars.termStructure.forwardRate(vars.settlement, vars.settlement + 30, d1, Compounding.Simple); if (ir.dayCounter().name() != d1.name()) { QAssert.Fail("PiecewiseYieldCurve forwardRate dayCounter error" + " Actual daycounter : " + vars.termStructure.dayCounter().name() + " Expetced DayCounter : " + d1.name()); } }
public void testActualActualWithAnnualSchedule() { // Testing actual/actual with schedule "for undefined annual reference periods // Now do an annual schedule Calendar calendar = new UnitedStates(); Schedule schedule = new MakeSchedule() .from(new Date(10, Month.January, 2017)) .withFirstDate(new Date(31, Month.August, 2017)) .to(new Date(28, Month.February, 2026)) .withFrequency(Frequency.Annual) .withCalendar(calendar) .withConvention(BusinessDayConvention.Unadjusted) .backwards().endOfMonth(false).value(); Date referencePeriodStart = schedule.date(1); Date referencePeriodEnd = schedule.date(2); Date testDate = schedule.date(1); DayCounter dayCounter = new ActualActual(ActualActual.Convention.ISMA, schedule); while (testDate < referencePeriodEnd) { double difference = ISMAYearFractionWithReferenceDates(dayCounter, testDate, referencePeriodEnd, referencePeriodStart, referencePeriodEnd) - dayCounter.yearFraction(testDate, referencePeriodEnd); if (Math.Abs(difference) > 1.0e-10) { QAssert.Fail("Failed to correctly use the schedule " + "to find the reference period for Act/Act:\n" + testDate + " to " + referencePeriodEnd + "\n Ref: " + referencePeriodStart + " to " + referencePeriodEnd); } testDate = calendar.advance(testDate, 1, TimeUnit.Days); } }
private double actualActualDaycountComputation(Schedule schedule, Date start, Date end) { DayCounter daycounter = new ActualActual(ActualActual.Convention.ISMA, schedule); double yearFraction = 0.0; for (int i = 1; i < schedule.size() - 1; i++) { Date referenceStart = schedule.date(i); Date referenceEnd = schedule.date(i + 1); if (start < referenceEnd && end > referenceStart) { yearFraction += ISMAYearFractionWithReferenceDates( daycounter, (start > referenceStart) ? start : referenceStart, (end < referenceEnd) ? end : referenceEnd, referenceStart, referenceEnd ); } ; } return(yearFraction); }
public void testActualActualWithSemiannualSchedule() { // Testing actual/actual with schedule for undefined semiannual reference periods Calendar calendar = new UnitedStates(); Date fromDate = new Date(10, Month.January, 2017); Date firstCoupon = new Date(31, Month.August, 2017); Date quasiCoupon = new Date(28, Month.February, 2017); Date quasiCoupon2 = new Date(31, Month.August, 2016); Schedule schedule = new MakeSchedule() .from(fromDate) .withFirstDate(firstCoupon) .to(new Date(28, Month.February, 2026)) .withFrequency(Frequency.Semiannual) .withCalendar(calendar) .withConvention(BusinessDayConvention.Unadjusted) .backwards().endOfMonth(true).value(); Date testDate = schedule.date(1); DayCounter dayCounter = new ActualActual(ActualActual.Convention.ISMA, schedule); DayCounter dayCounterNoSchedule = new ActualActual(ActualActual.Convention.ISMA); Date referencePeriodStart = schedule.date(1); Date referencePeriodEnd = schedule.date(2); // Test QAssert.IsTrue(dayCounter.yearFraction(referencePeriodStart, referencePeriodStart).IsEqual(0.0), "This should be zero."); QAssert.IsTrue(dayCounterNoSchedule.yearFraction(referencePeriodStart, referencePeriodStart).IsEqual(0.0), "This should be zero"); QAssert.IsTrue(dayCounterNoSchedule.yearFraction(referencePeriodStart, referencePeriodStart, referencePeriodStart, referencePeriodStart).IsEqual(0.0), "This should be zero"); QAssert.IsTrue(dayCounter.yearFraction(referencePeriodStart, referencePeriodEnd).IsEqual(0.5), "This should be exact using schedule; " + referencePeriodStart + " to " + referencePeriodEnd + "Should be 0.5"); QAssert.IsTrue(dayCounterNoSchedule.yearFraction(referencePeriodStart, referencePeriodEnd, referencePeriodStart, referencePeriodEnd).IsEqual(0.5), "This should be exact for explicit reference periods with no schedule"); while (testDate < referencePeriodEnd) { double difference = dayCounter.yearFraction(testDate, referencePeriodEnd, referencePeriodStart, referencePeriodEnd) - dayCounter.yearFraction(testDate, referencePeriodEnd); if (Math.Abs(difference) > 1.0e-10) { QAssert.Fail("Failed to correctly use the schedule to find the reference period for Act/Act"); } testDate = calendar.advance(testDate, 1, TimeUnit.Days); } //Test long first coupon double calculatedYearFraction = dayCounter.yearFraction(fromDate, firstCoupon); double expectedYearFraction = 0.5 + ((double)dayCounter.dayCount(fromDate, quasiCoupon)) / (2 * dayCounter.dayCount(quasiCoupon2, quasiCoupon)); QAssert.IsTrue(Math.Abs(calculatedYearFraction - expectedYearFraction) < 1.0e-10, "Failed to compute the expected year fraction " + "\n expected: " + expectedYearFraction + "\n calculated: " + calculatedYearFraction); // test multiple periods schedule = new MakeSchedule() .from(new Date(10, Month.January, 2017)) .withFirstDate(new Date(31, Month.August, 2017)) .to(new Date(28, Month.February, 2026)) .withFrequency(Frequency.Semiannual) .withCalendar(calendar) .withConvention(BusinessDayConvention.Unadjusted) .backwards().endOfMonth(false).value(); Date periodStartDate = schedule.date(1); Date periodEndDate = schedule.date(2); dayCounter = new ActualActual(ActualActual.Convention.ISMA, schedule); while (periodEndDate < schedule.date(schedule.size() - 2)) { double expected = actualActualDaycountComputation(schedule, periodStartDate, periodEndDate); double calculated = dayCounter.yearFraction(periodStartDate, periodEndDate); if (Math.Abs(expected - calculated) > 1e-8) { QAssert.Fail("Failed to compute the correct year fraction " + "given a schedule: " + periodStartDate + " to " + periodEndDate + "\n expected: " + expected + " calculated: " + calculated); } periodEndDate = calendar.advance(periodEndDate, 1, TimeUnit.Days); } }
static void Main(string[] args) { try { DateTime timer = DateTime.Now; Calendar calendar = new TARGET(); Date todaysDate = new Date(10, Month.March, 2004); // must be a business day todaysDate = calendar.adjust(todaysDate); Settings.setEvaluationDate(todaysDate); IborIndex yieldIndx = new Euribor3M(); int[] tenorsSwapMkt = { 5, 10, 15, 20, 25, 30 }; // rates ignoring counterparty risk: double[] ratesSwapmkt = { .03249, .04074, .04463, .04675, .04775, .04811 }; List <RateHelper> swapHelpers = new List <RateHelper>(); for (int i = 0; i < tenorsSwapMkt.Length; i++) { swapHelpers.Add(new SwapRateHelper(new Handle <Quote>(new SimpleQuote(ratesSwapmkt[i])), new Period(tenorsSwapMkt[i], TimeUnit.Years), new TARGET(), Frequency.Quarterly, BusinessDayConvention.ModifiedFollowing, new ActualActual(ActualActual.Convention.ISDA), yieldIndx)); } YieldTermStructure swapTS = new PiecewiseYieldCurve <Discount, LogLinear>(2, new TARGET(), swapHelpers, new ActualActual(ActualActual.Convention.ISDA)); swapTS.enableExtrapolation(); IPricingEngine riskFreeEngine = new DiscountingSwapEngine(new Handle <YieldTermStructure>(swapTS)); List <Handle <DefaultProbabilityTermStructure> > defaultIntensityTS = new List <Handle <DefaultProbabilityTermStructure> >(); int[] defaultTenors = { 0, 12, 36, 60, 84, 120, 180, 240, 300, 360 }; // months // Three risk levels: double[] intensitiesLow = { 0.0036, 0.0036, 0.0065, 0.0099, 0.0111, 0.0177, 0.0177, 0.0177, 0.0177, 0.0177, 0.0177 }; double[] intensitiesMedium = { 0.0202, 0.0202, 0.0231, 0.0266, 0.0278, 0.0349, 0.0349, 0.0349, 0.0349, 0.0349, 0.0349 }; double[] intensitiesHigh = { 0.0534, 0.0534, 0.0564, 0.06, 0.0614, 0.0696, 0.0696, 0.0696, 0.0696, 0.0696, 0.0696 }; // Recovery rates: double ctptyRRLow = 0.4, ctptyRRMedium = 0.35, ctptyRRHigh = 0.3; List <Date> defaultTSDates = new List <Date>(); List <double> intesitiesVLow = new List <double>(), intesitiesVMedium = new List <double>(), intesitiesVHigh = new List <double>(); for (int i = 0; i < defaultTenors.Length; i++) { defaultTSDates.Add(new TARGET().advance(todaysDate, new Period(defaultTenors[i], TimeUnit.Months))); intesitiesVLow.Add(intensitiesLow[i]); intesitiesVMedium.Add(intensitiesMedium[i]); intesitiesVHigh.Add(intensitiesHigh[i]); } defaultIntensityTS.Add(new Handle <DefaultProbabilityTermStructure>( new InterpolatedHazardRateCurve <BackwardFlat>( defaultTSDates, intesitiesVLow, new Actual360(), new TARGET()))); defaultIntensityTS.Add(new Handle <DefaultProbabilityTermStructure>( new InterpolatedHazardRateCurve <BackwardFlat>( defaultTSDates, intesitiesVMedium, new Actual360(), new TARGET()))); defaultIntensityTS.Add(new Handle <DefaultProbabilityTermStructure>( new InterpolatedHazardRateCurve <BackwardFlat>( defaultTSDates, intesitiesVHigh, new Actual360(), new TARGET()))); double blackVol = 0.15; IPricingEngine ctptySwapCvaLow = new CounterpartyAdjSwapEngine(new Handle <YieldTermStructure>(swapTS), blackVol, defaultIntensityTS[0], ctptyRRLow); IPricingEngine ctptySwapCvaMedium = new CounterpartyAdjSwapEngine(new Handle <YieldTermStructure>(swapTS), blackVol, defaultIntensityTS[1], ctptyRRMedium); IPricingEngine ctptySwapCvaHigh = new CounterpartyAdjSwapEngine(new Handle <YieldTermStructure>(swapTS), blackVol, defaultIntensityTS[2], ctptyRRHigh); defaultIntensityTS[0].link.enableExtrapolation(); defaultIntensityTS[1].link.enableExtrapolation(); defaultIntensityTS[2].link.enableExtrapolation(); // SWAP RISKY REPRICE---------------------------------------------- // fixed leg Frequency fixedLegFrequency = Frequency.Quarterly; BusinessDayConvention fixedLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter fixedLegDayCounter = new ActualActual(ActualActual.Convention.ISDA); DayCounter floatingLegDayCounter = new ActualActual(ActualActual.Convention.ISDA); VanillaSwap.Type swapType = //VanillaSwap::Receiver ; VanillaSwap.Type.Payer; IborIndex yieldIndxS = new Euribor3M(new Handle <YieldTermStructure>(swapTS)); List <VanillaSwap> riskySwaps = new List <VanillaSwap>(); for (int i = 0; i < tenorsSwapMkt.Length; i++) { riskySwaps.Add(new MakeVanillaSwap(new Period(tenorsSwapMkt[i], TimeUnit.Years), yieldIndxS, ratesSwapmkt[i], new Period(0, TimeUnit.Days)) .withSettlementDays(2) .withFixedLegDayCount(fixedLegDayCounter) .withFixedLegTenor(new Period(fixedLegFrequency)) .withFixedLegConvention(fixedLegConvention) .withFixedLegTerminationDateConvention(fixedLegConvention) .withFixedLegCalendar(calendar) .withFloatingLegCalendar(calendar) .withNominal(100.0) .withType(swapType).value()); } Console.WriteLine("-- Correction in the contract fix rate in bp --"); /* The paper plots correction to be substracted, here is printed * with its sign */ for (int i = 0; i < riskySwaps.Count; i++) { riskySwaps[i].setPricingEngine(riskFreeEngine); // should recover the input here: double nonRiskyFair = riskySwaps[i].fairRate(); Console.Write((tenorsSwapMkt[i]).ToString("0").PadLeft(6)); Console.Write(" | " + nonRiskyFair.ToString("P3").PadLeft(6)); // Low Risk: riskySwaps[i].setPricingEngine(ctptySwapCvaLow); Console.Write(" | " + (10000.0 * (riskySwaps[i].fairRate() - nonRiskyFair)).ToString("#0.00").PadLeft(6)); //cout << " | " << setw(6) << riskySwaps[i].NPV() ; // Medium Risk: riskySwaps[i].setPricingEngine(ctptySwapCvaMedium); Console.Write(" | " + (10000.0 * (riskySwaps[i].fairRate() - nonRiskyFair)).ToString("#0.00").PadLeft(6)); //cout << " | " << setw(6) << riskySwaps[i].NPV() ; riskySwaps[i].setPricingEngine(ctptySwapCvaHigh); Console.Write(" | " + (10000.0 * (riskySwaps[i].fairRate() - nonRiskyFair)).ToString("#0.00").PadLeft(6)); //cout << " | " << setw(6) << riskySwaps[i].NPV() ; Console.WriteLine(); } Console.WriteLine(); Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.WriteLine(); Console.Write("Press any key to continue ..."); Console.ReadKey(); } catch (Exception e) { Console.Write(e.Message); Console.Write("Press any key to continue ..."); Console.ReadKey(); } }
static void Main() { DateTime timer = DateTime.Now; /********************* *** MARKET DATA *** *********************/ RelinkableHandle <YieldTermStructure> euriborTermStructure = new RelinkableHandle <YieldTermStructure>(); IborIndex euribor3m = new Euribor3M(euriborTermStructure); Date todaysDate = new Date(23, Month.May, 2006); Settings.setEvaluationDate(todaysDate); Calendar calendar = euribor3m.fixingCalendar(); int fixingDays = euribor3m.fixingDays(); Date settlementDate = calendar.advance(todaysDate, fixingDays, TimeUnit.Days); Console.WriteLine("Today: " + todaysDate.DayOfWeek + ", " + todaysDate); Console.WriteLine("Settlement date: " + settlementDate.DayOfWeek + ", " + settlementDate); // 3 month term FRA quotes (index refers to monthsToStart) double[] threeMonthFraQuote = new double[10]; threeMonthFraQuote[1] = 0.030; threeMonthFraQuote[2] = 0.031; threeMonthFraQuote[3] = 0.032; threeMonthFraQuote[6] = 0.033; threeMonthFraQuote[9] = 0.034; /******************** *** 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. // FRAs SimpleQuote fra1x4Rate = new SimpleQuote(threeMonthFraQuote[1]); SimpleQuote fra2x5Rate = new SimpleQuote(threeMonthFraQuote[2]); SimpleQuote fra3x6Rate = new SimpleQuote(threeMonthFraQuote[3]); SimpleQuote fra6x9Rate = new SimpleQuote(threeMonthFraQuote[6]); SimpleQuote fra9x12Rate = new SimpleQuote(threeMonthFraQuote[9]); RelinkableHandle <Quote> h1x4 = new RelinkableHandle <Quote>(); h1x4.linkTo(fra1x4Rate); RelinkableHandle <Quote> h2x5 = new RelinkableHandle <Quote>(); h2x5.linkTo(fra2x5Rate); RelinkableHandle <Quote> h3x6 = new RelinkableHandle <Quote>(); h3x6.linkTo(fra3x6Rate); RelinkableHandle <Quote> h6x9 = new RelinkableHandle <Quote>(); h6x9.linkTo(fra6x9Rate); RelinkableHandle <Quote> h9x12 = new RelinkableHandle <Quote>(); h9x12.linkTo(fra9x12Rate); /********************* *** 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. DayCounter fraDayCounter = euribor3m.dayCounter(); BusinessDayConvention convention = euribor3m.businessDayConvention(); bool endOfMonth = euribor3m.endOfMonth(); RateHelper fra1x4 = new FraRateHelper(h1x4, 1, 4, fixingDays, calendar, convention, endOfMonth, fraDayCounter); RateHelper fra2x5 = new FraRateHelper(h2x5, 2, 5, fixingDays, calendar, convention, endOfMonth, fraDayCounter); RateHelper fra3x6 = new FraRateHelper(h3x6, 3, 6, fixingDays, calendar, convention, endOfMonth, fraDayCounter); RateHelper fra6x9 = new FraRateHelper(h6x9, 6, 9, fixingDays, calendar, convention, endOfMonth, fraDayCounter); RateHelper fra9x12 = new FraRateHelper(h9x12, 9, 12, fixingDays, calendar, convention, endOfMonth, fraDayCounter); /********************* ** 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 FRA curve List <RateHelper> fraInstruments = new List <RateHelper>(); fraInstruments.Add(fra1x4); fraInstruments.Add(fra2x5); fraInstruments.Add(fra3x6); fraInstruments.Add(fra6x9); fraInstruments.Add(fra9x12); YieldTermStructure fraTermStructure = new PiecewiseYieldCurve <Discount, LogLinear>( settlementDate, fraInstruments, termStructureDayCounter, new List <Handle <Quote> >(), new List <Date>(), tolerance); // Term structures used for pricing/discounting RelinkableHandle <YieldTermStructure> discountingTermStructure = new RelinkableHandle <YieldTermStructure>(); discountingTermStructure.linkTo(fraTermStructure); /*********************** *** construct FRA's *** ***********************/ Calendar fraCalendar = euribor3m.fixingCalendar(); BusinessDayConvention fraBusinessDayConvention = euribor3m.businessDayConvention(); Position.Type fraFwdType = Position.Type.Long; double fraNotional = 100.0; const int FraTermMonths = 3; int[] monthsToStart = new [] { 1, 2, 3, 6, 9 }; euriborTermStructure.linkTo(fraTermStructure); Console.WriteLine("\nTest FRA construction, NPV calculation, and FRA purchase\n"); int i; for (i = 0; i < monthsToStart.Length; i++) { Date fraValueDate = fraCalendar.advance( settlementDate, monthsToStart[i], TimeUnit.Months, fraBusinessDayConvention); Date fraMaturityDate = fraCalendar.advance( fraValueDate, FraTermMonths, TimeUnit.Months, fraBusinessDayConvention); double fraStrikeRate = threeMonthFraQuote[monthsToStart[i]]; ForwardRateAgreement myFRA = new ForwardRateAgreement(fraValueDate, fraMaturityDate, fraFwdType, fraStrikeRate, fraNotional, euribor3m, discountingTermStructure); Console.WriteLine("3m Term FRA, Months to Start: " + monthsToStart[i]); Console.WriteLine("strike FRA rate: {0:0.00%}", fraStrikeRate); Console.WriteLine("FRA 3m forward rate: {0:0.00%}", myFRA.forwardRate()); Console.WriteLine("FRA market quote: {0:0.00%}", threeMonthFraQuote[monthsToStart[i]]); Console.WriteLine("FRA spot value: " + myFRA.spotValue()); Console.WriteLine("FRA forward value: " + myFRA.forwardValue()); Console.WriteLine("FRA implied Yield: {0:0.00%}", myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Compounding.Simple, fraDayCounter)); Console.WriteLine("market Zero Rate: {0:0.00%}", discountingTermStructure.link.zeroRate(fraMaturityDate, fraDayCounter, Compounding.Simple)); Console.WriteLine("FRA NPV [should be zero]: {0}\n", myFRA.NPV()); } Console.WriteLine("\n"); Console.WriteLine("Now take a 100 basis-point upward shift in FRA quotes and examine NPV\n"); const double BpsShift = 0.01; threeMonthFraQuote[1] = 0.030 + BpsShift; threeMonthFraQuote[2] = 0.031 + BpsShift; threeMonthFraQuote[3] = 0.032 + BpsShift; threeMonthFraQuote[6] = 0.033 + BpsShift; threeMonthFraQuote[9] = 0.034 + BpsShift; fra1x4Rate.setValue(threeMonthFraQuote[1]); fra2x5Rate.setValue(threeMonthFraQuote[2]); fra3x6Rate.setValue(threeMonthFraQuote[3]); fra6x9Rate.setValue(threeMonthFraQuote[6]); fra9x12Rate.setValue(threeMonthFraQuote[9]); for (i = 0; i < monthsToStart.Length; i++) { Date fraValueDate = fraCalendar.advance( settlementDate, monthsToStart[i], TimeUnit.Months, fraBusinessDayConvention); Date fraMaturityDate = fraCalendar.advance( fraValueDate, FraTermMonths, TimeUnit.Months, fraBusinessDayConvention); double fraStrikeRate = threeMonthFraQuote[monthsToStart[i]] - BpsShift; ForwardRateAgreement myFRA = new ForwardRateAgreement(fraValueDate, fraMaturityDate, fraFwdType, fraStrikeRate, fraNotional, euribor3m, discountingTermStructure); Console.WriteLine("3m Term FRA, 100 notional, Months to Start: " + monthsToStart[i]); Console.WriteLine("strike FRA rate: {0:0.00%}", fraStrikeRate); Console.WriteLine("FRA 3m forward rate: {0:0.00%}", myFRA.forwardRate()); Console.WriteLine("FRA market quote: {0:0.00%}", threeMonthFraQuote[monthsToStart[i]]); Console.WriteLine("FRA spot value: " + myFRA.spotValue()); Console.WriteLine("FRA forward value: " + myFRA.forwardValue()); Console.WriteLine("FRA implied Yield: {0:0.00%}", myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Compounding.Simple, fraDayCounter)); Console.WriteLine("market Zero Rate: {0:0.00%}", discountingTermStructure.link.zeroRate(fraMaturityDate, fraDayCounter, Compounding.Simple)); Console.WriteLine("FRA NPV [should be positive]: {0}\n", myFRA.NPV()); } Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.WriteLine(); Console.Write("Press any key to continue ..."); Console.ReadKey(); }
// setup public CommonVars() { backup = new SavedSettings(); cleaner = new IndexHistoryCleaner(); nominalUK = new RelinkableHandle <YieldTermStructure>(); cpiUK = new RelinkableHandle <ZeroInflationTermStructure>(); hcpi = new RelinkableHandle <ZeroInflationTermStructure>(); zciisD = new List <Date>(); zciisR = new List <double>(); hii = new RelinkableHandle <ZeroInflationIndex>(); nominals = new InitializedList <double>(1, 1000000); // option variables frequency = Frequency.Annual; // usual setup volatility = 0.01; length = 7; calendar = new UnitedKingdom(); convention = BusinessDayConvention.ModifiedFollowing; Date today = new Date(25, Month.November, 2009); evaluationDate = calendar.adjust(today); Settings.setEvaluationDate(evaluationDate); settlementDays = 0; fixingDays = 0; settlement = calendar.advance(today, settlementDays, TimeUnit.Days); startDate = settlement; dcZCIIS = new ActualActual(); dcNominal = new ActualActual(); // uk rpi index // fixing data Date from = new Date(20, Month.July, 2007); Date to = new Date(20, Month.November, 2009); Schedule rpiSchedule = new MakeSchedule().from(from).to(to) .withTenor(new Period(1, TimeUnit.Months)) .withCalendar(new UnitedKingdom()) .withConvention(BusinessDayConvention.ModifiedFollowing).value(); double[] fixData = { 206.1, 207.3, 208.0, 208.9, 209.7, 210.9, 209.8, 211.4, 212.1, 214.0, 215.1, 216.8, 216.5, 217.2, 218.4, 217.7, 216, 212.9, 210.1, 211.4, 211.3, 211.5, 212.8, 213.4, 213.4, 213.4, 214.4, -999.0, -999.0 }; // link from cpi index to cpi TS bool interp = false;// this MUST be false because the observation lag is only 2 months // for ZCIIS; but not for contract if the contract uses a bigger lag. ii = new UKRPI(interp, hcpi); for (int i = 0; i < rpiSchedule.Count; i++) { ii.addFixing(rpiSchedule[i], fixData[i], true);// force overwrite in case multiple use } Datum[] nominalData = { new Datum(new Date(26, Month.November, 2009), 0.475), new Datum(new Date(2, Month.December, 2009), 0.47498), new Datum(new Date(29, Month.December, 2009), 0.49988), new Datum(new Date(25, Month.February, 2010), 0.59955), new Datum(new Date(18, Month.March, 2010), 0.65361), new Datum(new Date(25, Month.May, 2010), 0.82830), new Datum(new Date(17, Month.June, 2010), 0.7), new Datum(new Date(16, Month.September, 2010), 0.78960), new Datum(new Date(16, Month.December, 2010), 0.93762), new Datum(new Date(17, Month.March, 2011), 1.12037), new Datum(new Date(22, Month.September, 2011), 1.52011), new Datum(new Date(25, Month.November, 2011), 1.78399), new Datum(new Date(26, Month.November, 2012), 2.41170), new Datum(new Date(25, Month.November, 2013), 2.83935), new Datum(new Date(25, Month.November, 2014), 3.12888), new Datum(new Date(25, Month.November, 2015), 3.34298), new Datum(new Date(25, Month.November, 2016), 3.50632), new Datum(new Date(27, Month.November, 2017), 3.63666), new Datum(new Date(26, Month.November, 2018), 3.74723), new Datum(new Date(25, Month.November, 2019), 3.83988), new Datum(new Date(25, Month.November, 2021), 4.00508), new Datum(new Date(25, Month.November, 2024), 4.16042), new Datum(new Date(26, Month.November, 2029), 4.15577), new Datum(new Date(27, Month.November, 2034), 4.04933), new Datum(new Date(25, Month.November, 2039), 3.95217), new Datum(new Date(25, Month.November, 2049), 3.80932), new Datum(new Date(25, Month.November, 2059), 3.80849), new Datum(new Date(25, Month.November, 2069), 3.72677), new Datum(new Date(27, Month.November, 2079), 3.63082) }; int nominalDataLength = 30 - 1; List <Date> nomD = new List <Date>(); List <double> nomR = new List <double>(); for (int i = 0; i < nominalDataLength; i++) { nomD.Add(nominalData[i].date); nomR.Add(nominalData[i].rate / 100.0); } YieldTermStructure nominal = new InterpolatedZeroCurve <Linear>(nomD, nomR, dcNominal); nominalUK.linkTo(nominal); // now build the zero inflation curve observationLag = new Period(2, TimeUnit.Months); contractObservationLag = new Period(3, TimeUnit.Months); contractObservationInterpolation = InterpolationType.Flat; Datum[] zciisData = { new Datum(new Date(25, Month.November, 2010), 3.0495), new Datum(new Date(25, Month.November, 2011), 2.93), new Datum(new Date(26, Month.November, 2012), 2.9795), new Datum(new Date(25, Month.November, 2013), 3.029), new Datum(new Date(25, Month.November, 2014), 3.1425), new Datum(new Date(25, Month.November, 2015), 3.211), new Datum(new Date(25, Month.November, 2016), 3.2675), new Datum(new Date(25, Month.November, 2017), 3.3625), new Datum(new Date(25, Month.November, 2018), 3.405), new Datum(new Date(25, Month.November, 2019), 3.48), new Datum(new Date(25, Month.November, 2021), 3.576), new Datum(new Date(25, Month.November, 2024), 3.649), new Datum(new Date(26, Month.November, 2029), 3.751), new Datum(new Date(27, Month.November, 2034), 3.77225), new Datum(new Date(25, Month.November, 2039), 3.77), new Datum(new Date(25, Month.November, 2049), 3.734), new Datum(new Date(25, Month.November, 2059), 3.714) }; zciisDataLength = 17; for (int i = 0; i < zciisDataLength; i++) { zciisD.Add(zciisData[i].date); zciisR.Add(zciisData[i].rate); } // now build the helpers ... List <BootstrapHelper <ZeroInflationTermStructure> > helpers = makeHelpers(zciisData, zciisDataLength, ii, observationLag, calendar, convention, dcZCIIS); // we can use historical or first ZCIIS for this // we know historical is WAY off market-implied, so use market implied flat. double baseZeroRate = zciisData[0].rate / 100.0; PiecewiseZeroInflationCurve <Linear> pCPIts = new PiecewiseZeroInflationCurve <Linear>( evaluationDate, calendar, dcZCIIS, observationLag, ii.frequency(), ii.interpolated(), baseZeroRate, new Handle <YieldTermStructure>(nominalUK), helpers); pCPIts.recalculate(); cpiUK.linkTo(pCPIts); // make sure that the index has the latest zero inflation term structure hcpi.linkTo(pCPIts); }
public ActualActual(ActualActual.Convention c) : this(NQuantLibcPINVOKE.new_ActualActual__SWIG_0((int)c), true) { if (NQuantLibcPINVOKE.SWIGPendingException.Pending) throw NQuantLibcPINVOKE.SWIGPendingException.Retrieve(); }
static void Main(string[] args) { DateTime timer = DateTime.Now; /********************* *** MARKET DATA *** *********************/ Calendar calendar = new TARGET(); Date settlementDate = new Date(18, Month.September, 2008); // must be a business day settlementDate = calendar.adjust(settlementDate); int fixingDays = 3; int settlementDays = 3; Date todaysDate = calendar.advance(settlementDate, -fixingDays, TimeUnit.Days); // nothing to do with Date::todaysDate Settings.setEvaluationDate(todaysDate); Console.WriteLine("Today: {0}, {1}", todaysDate.DayOfWeek, todaysDate); Console.WriteLine("Settlement date: {0}, {1}", settlementDate.DayOfWeek, settlementDate); // Building of the bonds discounting yield curve /********************* *** RATE HELPERS *** *********************/ // RateHelpers are built from the above quotes together with // other instrument dependant infos. Quotes are passed in // relinkable handles which could be relinked to some other // data source later. // Common data // ZC rates for the short end double zc3mQuote=0.0096; double zc6mQuote=0.0145; double zc1yQuote=0.0194; Quote zc3mRate = new SimpleQuote(zc3mQuote); Quote zc6mRate = new SimpleQuote(zc6mQuote); Quote zc1yRate = new SimpleQuote(zc1yQuote); DayCounter zcBondsDayCounter = new Actual365Fixed(); RateHelper zc3m = new DepositRateHelper(new Handle<Quote>(zc3mRate), new Period(3, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); RateHelper zc6m = new DepositRateHelper(new Handle<Quote>(zc6mRate), new Period(6, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); RateHelper zc1y = new DepositRateHelper(new Handle<Quote>(zc1yRate), new Period(1, TimeUnit.Years), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, zcBondsDayCounter); // setup bonds double redemption = 100.0; const int numberOfBonds = 5; Date[] issueDates = { new Date (15, Month.March, 2005), new Date (15, Month.June, 2005), new Date (30, Month.June, 2006), new Date (15, Month.November, 2002), new Date (15, Month.May, 1987) }; Date[] maturities = { new Date (31, Month.August, 2010), new Date (31, Month.August, 2011), new Date (31, Month.August, 2013), new Date (15, Month.August, 2018), new Date (15, Month.May, 2038) }; double[] couponRates = { 0.02375, 0.04625, 0.03125, 0.04000, 0.04500 }; double[] marketQuotes = { 100.390625, 106.21875, 100.59375, 101.6875, 102.140625 }; List<SimpleQuote> quote = new List<SimpleQuote>(); for (int i=0; i<numberOfBonds; i++) { SimpleQuote cp = new SimpleQuote(marketQuotes[i]); quote.Add(cp); } List<RelinkableHandle<Quote>> quoteHandle = new InitializedList<RelinkableHandle<Quote>>(numberOfBonds); for (int i=0; i<numberOfBonds; i++) { quoteHandle[i].linkTo(quote[i]); } // Definition of the rate helpers List<FixedRateBondHelper> bondsHelpers = new List<FixedRateBondHelper>(); for (int i=0; i<numberOfBonds; i++) { Schedule schedule = new Schedule(issueDates[i], maturities[i], new Period(Frequency.Semiannual), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBondHelper bondHelper = new FixedRateBondHelper(quoteHandle[i], settlementDays, 100.0, schedule, new List<double>() { couponRates[i] }, new ActualActual(ActualActual.Convention.Bond), BusinessDayConvention.Unadjusted, redemption, issueDates[i]); bondsHelpers.Add(bondHelper); } /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 DayCounter termStructureDayCounter = new ActualActual(ActualActual.Convention.ISDA); double tolerance = 1.0e-15; // A depo-bond curve List<RateHelper> bondInstruments = new List<RateHelper>(); // Adding the ZC bonds to the curve for the short end bondInstruments.Add(zc3m); bondInstruments.Add(zc6m); bondInstruments.Add(zc1y); // Adding the Fixed rate bonds to the curve for the long end for (int i=0; i<numberOfBonds; i++) { bondInstruments.Add(bondsHelpers[i]); } YieldTermStructure bondDiscountingTermStructure = new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, bondInstruments, termStructureDayCounter, new List<Handle<Quote>>(), new List<Date>(), tolerance); // Building of the Libor forecasting curve // deposits double d1wQuote=0.043375; double d1mQuote=0.031875; double d3mQuote=0.0320375; double d6mQuote=0.03385; double d9mQuote=0.0338125; double d1yQuote=0.0335125; // swaps double s2yQuote=0.0295; double s3yQuote=0.0323; double s5yQuote=0.0359; double s10yQuote=0.0412; double s15yQuote=0.0433; /******************** *** QUOTES *** ********************/ // SimpleQuote stores a value which can be manually changed; // other Quote subclasses could read the value from a database // or some kind of data feed. // deposits Quote d1wRate = new SimpleQuote(d1wQuote); Quote d1mRate = new SimpleQuote(d1mQuote); Quote d3mRate = new SimpleQuote(d3mQuote); Quote d6mRate = new SimpleQuote(d6mQuote); Quote d9mRate = new SimpleQuote(d9mQuote); Quote d1yRate = new SimpleQuote(d1yQuote); // swaps Quote s2yRate = new SimpleQuote(s2yQuote); Quote s3yRate = new SimpleQuote(s3yQuote); Quote s5yRate = new SimpleQuote(s5yQuote); Quote s10yRate = new SimpleQuote(s10yQuote); Quote s15yRate = new SimpleQuote(s15yQuote); /********************* *** RATE HELPERS *** *********************/ // RateHelpers are built from the above quotes together with // other instrument dependant infos. Quotes are passed in // relinkable handles which could be relinked to some other // data source later. // deposits DayCounter depositDayCounter = new Actual360(); RateHelper d1w = new DepositRateHelper( new Handle<Quote>(d1wRate), new Period(1, TimeUnit.Weeks), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d1m = new DepositRateHelper( new Handle<Quote>(d1mRate), new Period(1, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d3m = new DepositRateHelper( new Handle<Quote>(d3mRate), new Period(3, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d6m = new DepositRateHelper( new Handle<Quote>(d6mRate), new Period(6, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d9m = new DepositRateHelper( new Handle<Quote>(d9mRate), new Period(9, TimeUnit.Months), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); RateHelper d1y = new DepositRateHelper( new Handle<Quote>(d1yRate), new Period(1, TimeUnit.Years), fixingDays, calendar, BusinessDayConvention.ModifiedFollowing, true, depositDayCounter); // setup swaps Frequency swFixedLegFrequency =Frequency.Annual; BusinessDayConvention swFixedLegConvention = BusinessDayConvention.Unadjusted; DayCounter swFixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.European); IborIndex swFloatingLegIndex = new Euribor6M(); Period forwardStart = new Period(1, TimeUnit.Days); RateHelper s2y = new SwapRateHelper( new Handle<Quote>(s2yRate), new Period(2, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); RateHelper s3y = new SwapRateHelper( new Handle<Quote>(s3yRate), new Period(3, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); RateHelper s5y = new SwapRateHelper( new Handle<Quote>(s5yRate), new Period(5, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); RateHelper s10y = new SwapRateHelper( new Handle<Quote>(s10yRate), new Period(10, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); RateHelper s15y = new SwapRateHelper( new Handle<Quote>(s15yRate), new Period(15, TimeUnit.Years), calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, new Handle<Quote>(),forwardStart); /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 // A depo-swap curve List<RateHelper> depoSwapInstruments = new List<RateHelper>(); depoSwapInstruments.Add(d1w); depoSwapInstruments.Add(d1m); depoSwapInstruments.Add(d3m); depoSwapInstruments.Add(d6m); depoSwapInstruments.Add(d9m); depoSwapInstruments.Add(d1y); depoSwapInstruments.Add(s2y); depoSwapInstruments.Add(s3y); depoSwapInstruments.Add(s5y); depoSwapInstruments.Add(s10y); depoSwapInstruments.Add(s15y); YieldTermStructure depoSwapTermStructure = new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoSwapInstruments, termStructureDayCounter, new List<Handle<Quote> >(), new List<Date>(), tolerance); // Term structures that will be used for pricing: // the one used for discounting cash flows RelinkableHandle<YieldTermStructure> discountingTermStructure = new RelinkableHandle<YieldTermStructure>(); // the one used for forward rate forecasting RelinkableHandle<YieldTermStructure> forecastingTermStructure = new RelinkableHandle<YieldTermStructure>(); /********************* * BONDS TO BE PRICED * **********************/ // Common data double faceAmount = 100; // Pricing engine IPricingEngine bondEngine = new DiscountingBondEngine(discountingTermStructure); // Zero coupon bond ZeroCouponBond zeroCouponBond = new ZeroCouponBond( settlementDays, new UnitedStates(UnitedStates.Market.GovernmentBond), faceAmount, new Date(15, Month.August,2013), BusinessDayConvention.Following, 116.92, new Date(15, Month.August,2003)); zeroCouponBond.setPricingEngine(bondEngine); // Fixed 4.5% US Treasury Note Schedule fixedBondSchedule = new Schedule(new Date(15, Month.May, 2007), new Date(15,Month.May,2017), new Period(Frequency.Semiannual), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBond fixedRateBond = new FixedRateBond( settlementDays, faceAmount, fixedBondSchedule, new List<double>() { 0.045 }, new ActualActual(ActualActual.Convention.Bond), BusinessDayConvention.ModifiedFollowing, 100.0, new Date(15, Month.May, 2007)); fixedRateBond.setPricingEngine(bondEngine); // Floating rate bond (3M USD Libor + 0.1%) // Should and will be priced on another curve later... RelinkableHandle<YieldTermStructure> liborTermStructure = new RelinkableHandle<YieldTermStructure>(); IborIndex libor3m = new USDLibor(new Period(3, TimeUnit.Months), liborTermStructure); libor3m.addFixing(new Date(17, Month.July, 2008),0.0278625); Schedule floatingBondSchedule = new Schedule(new Date(21, Month.October, 2005), new Date(21, Month.October, 2010), new Period(Frequency.Quarterly), new UnitedStates(UnitedStates.Market.NYSE), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, true); FloatingRateBond floatingRateBond = new FloatingRateBond( settlementDays, faceAmount, floatingBondSchedule, libor3m, new Actual360(), BusinessDayConvention.ModifiedFollowing, 2, // Gearings new List<double>() { 1.0 }, // Spreads new List<double>() { 0.001 }, // Caps new List<double>(), // Floors new List<double>(), // Fixing in arrears true, 100.0, new Date(21, Month.October, 2005)); floatingRateBond.setPricingEngine(bondEngine); // Coupon pricers IborCouponPricer pricer = new BlackIborCouponPricer(); // optionLet volatilities double volatility = 0.0; Handle<OptionletVolatilityStructure> vol; vol = new Handle<OptionletVolatilityStructure>( new ConstantOptionletVolatility( settlementDays, calendar, BusinessDayConvention.ModifiedFollowing, volatility, new Actual365Fixed())); pricer.setCapletVolatility(vol); Utils.setCouponPricer(floatingRateBond.cashflows(),pricer); // Yield curve bootstrapping forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(bondDiscountingTermStructure); // We are using the depo & swap curve to estimate the future Libor rates liborTermStructure.linkTo(depoSwapTermStructure); /*************** * BOND PRICING * ****************/ // write column headings int[] widths = { 18, 10, 10, 10 }; Console.WriteLine("{0,18}{1,10}{2,10}{3,10}", "", "ZC", "Fixed", "Floating"); string separator = " | "; int width = widths[0] + widths[1] + widths[2] + widths[3]; string rule = "".PadLeft(width, '-'), dblrule = "".PadLeft(width, '='); string tab = "".PadLeft(8, ' '); Console.WriteLine(rule); Console.WriteLine("Net present value".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.NPV(), fixedRateBond.NPV(), floatingRateBond.NPV()); Console.WriteLine("Clean price".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.cleanPrice(), fixedRateBond.cleanPrice(), floatingRateBond.cleanPrice()); Console.WriteLine("Dirty price".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.dirtyPrice(), fixedRateBond.dirtyPrice(), floatingRateBond.dirtyPrice()); Console.WriteLine("Accrued coupon".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}", zeroCouponBond.accruedAmount(), fixedRateBond.accruedAmount(), floatingRateBond.accruedAmount()); Console.WriteLine("Previous coupon".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}", "N/A", fixedRateBond.previousCoupon(), floatingRateBond.previousCoupon()); Console.WriteLine("Next coupon".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}", "N/A", fixedRateBond.nextCoupon(), floatingRateBond.nextCoupon()); Console.WriteLine("Yield".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}", zeroCouponBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual), fixedRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual), floatingRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual)); Console.WriteLine(); // Other computations Console.WriteLine("Sample indirect computations (for the floating rate bond): "); Console.WriteLine(rule); Console.WriteLine("Yield to Clean Price: {0:n2}", floatingRateBond.cleanPrice(floatingRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual), new Actual360(), Compounding.Compounded, Frequency.Annual, settlementDate)); Console.WriteLine("Clean Price to Yield: {0:0.00%}", floatingRateBond.yield(floatingRateBond.cleanPrice(),new Actual360(), Compounding.Compounded, Frequency.Annual, settlementDate)); /* "Yield to Price" "Price to Yield" */ Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.WriteLine(); Console.Write("Press any key to continue ..."); Console.ReadKey(); }
static void Main(string[] args) { // boost::timer timer; Date today = new Date(16, Month.October, 2007); Settings.setEvaluationDate(today); Console.WriteLine(); Console.WriteLine("Pricing a callable fixed rate bond using"); Console.WriteLine("Hull White model w/ reversion parameter = 0.03"); Console.WriteLine("BAC4.65 09/15/12 ISIN: US06060WBJ36"); Console.WriteLine("roughly five year tenor, quarterly coupon and call dates"); Console.WriteLine("reference date is : " + today.ToLongDateString()); Console.WriteLine(""); /* Bloomberg OAS1: "N" model (Hull White) * varying volatility parameter * * The curve entered into Bloomberg OAS1 is a flat curve, * at constant yield = 5.5%, semiannual compounding. * Assume here OAS1 curve uses an ACT/ACT day counter, * as documented in PFC1 as a "default" in the latter case. */ // set up a flat curve corresponding to Bloomberg flat curve double bbCurveRate = 0.055; DayCounter bbDayCounter = new ActualActual(ActualActual.Convention.Bond); InterestRate bbIR = new InterestRate(bbCurveRate, bbDayCounter, Compounding.Compounded, Frequency.Semiannual); Handle <YieldTermStructure> termStructure = new Handle <YieldTermStructure>(flatRate(today, bbIR.rate(), bbIR.dayCounter(), bbIR.compounding(), bbIR.frequency())); // set up the call schedule CallabilitySchedule callSchedule = new CallabilitySchedule(); double callPrice = 100.0; int numberOfCallDates = 24; Date callDate = new Date(15, Month.September, 2006); for (int i = 0; i < numberOfCallDates; i++) { Calendar nullCalendar = new NullCalendar(); Callability.Price myPrice = new Callability.Price(callPrice, Callability.Price.Type.Clean); callSchedule.Add(new Callability(myPrice, Callability.Type.Call, callDate)); callDate = nullCalendar.advance(callDate, 3, TimeUnit.Months); } // set up the callable bond Date dated = new Date(16, Month.September, 2004); Date issue = dated; Date maturity = new Date(15, Month.September, 2012); int settlementDays = 3; // Bloomberg OAS1 settle is Oct 19, 2007 Calendar bondCalendar = new UnitedStates(UnitedStates.Market.GovernmentBond); double coupon = .0465; Frequency frequency = Frequency.Quarterly; double redemption = 100.0; double faceAmount = 100.0; /* The 30/360 day counter Bloomberg uses for this bond cannot * reproduce the US Bond/ISMA (constant) cashflows used in PFC1. * Therefore use ActAct(Bond) */ DayCounter bondDayCounter = new ActualActual(ActualActual.Convention.Bond); // PFC1 shows no indication dates are being adjusted // for weekends/holidays for vanilla bonds BusinessDayConvention accrualConvention = BusinessDayConvention.Unadjusted; BusinessDayConvention paymentConvention = BusinessDayConvention.Unadjusted; Schedule sch = new Schedule(dated, maturity, new Period(frequency), bondCalendar, accrualConvention, accrualConvention, DateGeneration.Rule.Backward, false); int maxIterations = 1000; double accuracy = 1e-8; int gridIntervals = 40; double reversionParameter = .03; // output price/yield results for varying volatility parameter double sigma = Const.QL_EPSILON; // core dumps if zero on Cygwin ShortRateModel hw0 = new HullWhite(termStructure, reversionParameter, sigma); IPricingEngine engine0 = new TreeCallableFixedRateBondEngine(hw0, gridIntervals, termStructure); CallableFixedRateBond callableBond = new CallableFixedRateBond(settlementDays, faceAmount, sch, new InitializedList <double>(1, coupon), bondDayCounter, paymentConvention, redemption, issue, callSchedule); callableBond.setPricingEngine(engine0); Console.WriteLine("sigma/vol (%) = {0:0.00}", (100.0 * sigma)); Console.WriteLine("QLNet price/yld (%) {0:0.00} / {1:0.00} ", callableBond.cleanPrice(), 100.0 * callableBond.yield(bondDayCounter, Compounding.Compounded, frequency, accuracy, maxIterations)); Console.WriteLine("Bloomberg price/yld (%) 96,50 / 5,47"); Console.WriteLine(""); // sigma = .01; Console.WriteLine("sigma/vol (%) = {0:0.00}", (100.0 * sigma)); ShortRateModel hw1 = new HullWhite(termStructure, reversionParameter, sigma); IPricingEngine engine1 = new TreeCallableFixedRateBondEngine(hw1, gridIntervals, termStructure); callableBond.setPricingEngine(engine1); Console.WriteLine("QLNet price/yld (%) {0:0.00} / {1:0.00} ", callableBond.cleanPrice(), 100.0 * callableBond.yield(bondDayCounter, Compounding.Compounded, frequency, accuracy, maxIterations)); Console.WriteLine("Bloomberg price/yld (%) 95,68 / 5,66"); Console.WriteLine(""); // sigma = .03; Console.WriteLine("sigma/vol (%) = {0:0.00}", (100.0 * sigma)); ShortRateModel hw2 = new HullWhite(termStructure, reversionParameter, sigma); IPricingEngine engine2 = new TreeCallableFixedRateBondEngine(hw2, gridIntervals, termStructure); callableBond.setPricingEngine(engine2); Console.WriteLine("QLNet price/yld (%) {0:0.00} / {1:0.00} ", callableBond.cleanPrice(), 100.0 * callableBond.yield(bondDayCounter, Compounding.Compounded, frequency, accuracy, maxIterations)); Console.WriteLine("Bloomberg price/yld (%) 92,34 / 6,49"); Console.WriteLine(""); // sigma = .06; Console.WriteLine("sigma/vol (%) = {0:0.00}", (100.0 * sigma)); ShortRateModel hw3 = new HullWhite(termStructure, reversionParameter, sigma); IPricingEngine engine3 = new TreeCallableFixedRateBondEngine(hw3, gridIntervals, termStructure); callableBond.setPricingEngine(engine3); Console.WriteLine("QLNet price/yld (%) {0:0.00} / {1:0.00} ", callableBond.cleanPrice(), 100.0 * callableBond.yield(bondDayCounter, Compounding.Compounded, frequency, accuracy, maxIterations)); Console.WriteLine("Bloomberg price/yld (%) 87,16 / 7,83"); Console.WriteLine(""); // sigma = .12; Console.WriteLine("sigma/vol (%) = {0:0.00}", (100.0 * sigma)); ShortRateModel hw4 = new HullWhite(termStructure, reversionParameter, sigma); IPricingEngine engine4 = new TreeCallableFixedRateBondEngine(hw4, gridIntervals, termStructure); callableBond.setPricingEngine(engine4); Console.WriteLine("QLNet price/yld (%) {0:0.00} / {1:0.00} ", callableBond.cleanPrice(), 100.0 * callableBond.yield(bondDayCounter, Compounding.Compounded, frequency, accuracy, maxIterations)); Console.WriteLine("Bloomberg price/yld (%) 77,31 / 10,65"); }
static void Main() { DateTime timer = DateTime.Now; /********************* *** MARKET DATA *** *********************/ RelinkableHandle<YieldTermStructure> euriborTermStructure = new RelinkableHandle<YieldTermStructure>(); IborIndex euribor3m = new Euribor3M(euriborTermStructure); Date todaysDate = new Date(23, Month.May, 2006); Settings.setEvaluationDate(todaysDate); Calendar calendar = euribor3m.fixingCalendar(); int fixingDays = euribor3m.fixingDays(); Date settlementDate = calendar.advance(todaysDate, fixingDays, TimeUnit.Days); Console.WriteLine("Today: " + todaysDate.DayOfWeek + ", " + todaysDate); Console.WriteLine("Settlement date: " + settlementDate.DayOfWeek + ", " + settlementDate); // 3 month term FRA quotes (index refers to monthsToStart) double[] threeMonthFraQuote = new double[10]; threeMonthFraQuote[1]=0.030; threeMonthFraQuote[2]=0.031; threeMonthFraQuote[3]=0.032; threeMonthFraQuote[6]=0.033; threeMonthFraQuote[9]=0.034; /******************** *** 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. // FRAs SimpleQuote fra1x4Rate = new SimpleQuote(threeMonthFraQuote[1]); SimpleQuote fra2x5Rate = new SimpleQuote(threeMonthFraQuote[2]); SimpleQuote fra3x6Rate = new SimpleQuote(threeMonthFraQuote[3]); SimpleQuote fra6x9Rate = new SimpleQuote(threeMonthFraQuote[6]); SimpleQuote fra9x12Rate = new SimpleQuote(threeMonthFraQuote[9]); RelinkableHandle<Quote> h1x4 = new RelinkableHandle<Quote>(); h1x4.linkTo(fra1x4Rate); RelinkableHandle<Quote> h2x5 = new RelinkableHandle<Quote>(); h2x5.linkTo(fra2x5Rate); RelinkableHandle<Quote> h3x6 = new RelinkableHandle<Quote>(); h3x6.linkTo(fra3x6Rate); RelinkableHandle<Quote> h6x9 = new RelinkableHandle<Quote>(); h6x9.linkTo(fra6x9Rate); RelinkableHandle<Quote> h9x12 = new RelinkableHandle<Quote>(); h9x12.linkTo(fra9x12Rate); /********************* *** 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. DayCounter fraDayCounter = euribor3m.dayCounter(); BusinessDayConvention convention = euribor3m.businessDayConvention(); bool endOfMonth = euribor3m.endOfMonth(); RateHelper fra1x4 = new FraRateHelper(h1x4, 1, 4, fixingDays, calendar, convention, endOfMonth, fraDayCounter); RateHelper fra2x5 = new FraRateHelper(h2x5, 2, 5, fixingDays, calendar, convention, endOfMonth, fraDayCounter); RateHelper fra3x6 = new FraRateHelper(h3x6, 3, 6, fixingDays, calendar, convention, endOfMonth, fraDayCounter); RateHelper fra6x9 = new FraRateHelper(h6x9, 6, 9, fixingDays, calendar, convention, endOfMonth, fraDayCounter); RateHelper fra9x12 = new FraRateHelper(h9x12, 9, 12, fixingDays, calendar, convention, endOfMonth, fraDayCounter); /********************* ** 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 FRA curve List<RateHelper> fraInstruments = new List<RateHelper>(); fraInstruments.Add(fra1x4); fraInstruments.Add(fra2x5); fraInstruments.Add(fra3x6); fraInstruments.Add(fra6x9); fraInstruments.Add(fra9x12); YieldTermStructure fraTermStructure = new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, fraInstruments, termStructureDayCounter, new List<Handle<Quote>>(), new List<Date>(), tolerance); // Term structures used for pricing/discounting RelinkableHandle<YieldTermStructure> discountingTermStructure = new RelinkableHandle<YieldTermStructure>(); discountingTermStructure.linkTo(fraTermStructure); /*********************** *** construct FRA's *** ***********************/ Calendar fraCalendar = euribor3m.fixingCalendar(); BusinessDayConvention fraBusinessDayConvention = euribor3m.businessDayConvention(); Position.Type fraFwdType = Position.Type.Long; double fraNotional = 100.0; const int FraTermMonths = 3; int[] monthsToStart = new [] { 1, 2, 3, 6, 9 }; euriborTermStructure.linkTo(fraTermStructure); Console.WriteLine("\nTest FRA construction, NPV calculation, and FRA purchase\n"); int i; for (i=0; i<monthsToStart.Length; i++) { Date fraValueDate = fraCalendar.advance( settlementDate,monthsToStart[i], TimeUnit.Months, fraBusinessDayConvention); Date fraMaturityDate = fraCalendar.advance( fraValueDate, FraTermMonths, TimeUnit.Months, fraBusinessDayConvention); double fraStrikeRate = threeMonthFraQuote[monthsToStart[i]]; ForwardRateAgreement myFRA = new ForwardRateAgreement(fraValueDate, fraMaturityDate, fraFwdType,fraStrikeRate, fraNotional, euribor3m, discountingTermStructure); Console.WriteLine("3m Term FRA, Months to Start: " + monthsToStart[i]); Console.WriteLine("strike FRA rate: {0:0.00%}", fraStrikeRate); Console.WriteLine("FRA 3m forward rate: {0:0.00%}", myFRA.forwardRate()); Console.WriteLine("FRA market quote: {0:0.00%}", threeMonthFraQuote[monthsToStart[i]]); Console.WriteLine("FRA spot value: " + myFRA.spotValue()); Console.WriteLine("FRA forward value: " + myFRA.forwardValue()); Console.WriteLine("FRA implied Yield: {0:0.00%}", myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Compounding.Simple, fraDayCounter)); Console.WriteLine("market Zero Rate: {0:0.00%}", discountingTermStructure.link.zeroRate(fraMaturityDate, fraDayCounter, Compounding.Simple)); Console.WriteLine("FRA NPV [should be zero]: {0}\n", myFRA.NPV()); } Console.WriteLine("\n"); Console.WriteLine("Now take a 100 basis-point upward shift in FRA quotes and examine NPV\n"); const double BpsShift = 0.01; threeMonthFraQuote[1]=0.030+BpsShift; threeMonthFraQuote[2]=0.031+BpsShift; threeMonthFraQuote[3]=0.032+BpsShift; threeMonthFraQuote[6]=0.033+BpsShift; threeMonthFraQuote[9]=0.034+BpsShift; fra1x4Rate.setValue(threeMonthFraQuote[1]); fra2x5Rate.setValue(threeMonthFraQuote[2]); fra3x6Rate.setValue(threeMonthFraQuote[3]); fra6x9Rate.setValue(threeMonthFraQuote[6]); fra9x12Rate.setValue(threeMonthFraQuote[9]); for (i=0; i<monthsToStart.Length; i++) { Date fraValueDate = fraCalendar.advance( settlementDate, monthsToStart[i], TimeUnit.Months, fraBusinessDayConvention); Date fraMaturityDate = fraCalendar.advance( fraValueDate, FraTermMonths, TimeUnit.Months, fraBusinessDayConvention); double fraStrikeRate = threeMonthFraQuote[monthsToStart[i]] - BpsShift; ForwardRateAgreement myFRA = new ForwardRateAgreement(fraValueDate, fraMaturityDate, fraFwdType, fraStrikeRate, fraNotional, euribor3m, discountingTermStructure); Console.WriteLine("3m Term FRA, 100 notional, Months to Start: " + monthsToStart[i]); Console.WriteLine("strike FRA rate: {0:0.00%}", fraStrikeRate); Console.WriteLine("FRA 3m forward rate: {0:0.00%}", myFRA.forwardRate()); Console.WriteLine("FRA market quote: {0:0.00%}", threeMonthFraQuote[monthsToStart[i]]); Console.WriteLine("FRA spot value: " + myFRA.spotValue()); Console.WriteLine("FRA forward value: " + myFRA.forwardValue()); Console.WriteLine("FRA implied Yield: {0:0.00%}", myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Compounding.Simple, fraDayCounter)); Console.WriteLine("market Zero Rate: {0:0.00%}", discountingTermStructure.link.zeroRate(fraMaturityDate, fraDayCounter, Compounding.Simple)); Console.WriteLine("FRA NPV [should be positive]: {0}\n", myFRA.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(); } }
public void testCached() { // ("Testing bond price/yield calculation against cached values..."); CommonVars vars = new CommonVars(); // with implicit settlement calculation: Date today = new Date(22, Month.November, 2004); Settings.setEvaluationDate(today); Calendar bondCalendar = new NullCalendar(); DayCounter bondDayCount = new ActualActual(ActualActual.Convention.ISMA); int settlementDays = 1; var discountCurve = new Handle <YieldTermStructure>(Utilities.flatRate(today, new SimpleQuote(0.03), new Actual360())); // actual market values from the evaluation date Frequency freq = Frequency.Semiannual; Schedule sch1 = new Schedule(new Date(31, Month.October, 2004), new Date(31, Month.October, 2006), new Period(freq), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBond bond1 = new FixedRateBond(settlementDays, vars.faceAmount, sch1, new List <double>() { 0.025 }, bondDayCount, BusinessDayConvention.ModifiedFollowing, 100.0, new Date(1, Month.November, 2004)); IPricingEngine bondEngine = new DiscountingBondEngine(discountCurve); bond1.setPricingEngine(bondEngine); double marketPrice1 = 99.203125; double marketYield1 = 0.02925; Schedule sch2 = new Schedule(new Date(15, Month.November, 2004), new Date(15, Month.November, 2009), new Period(freq), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBond bond2 = new FixedRateBond(settlementDays, vars.faceAmount, sch2, new List <double>() { 0.035 }, bondDayCount, BusinessDayConvention.ModifiedFollowing, 100.0, new Date(15, Month.November, 2004)); bond2.setPricingEngine(bondEngine); double marketPrice2 = 99.6875; double marketYield2 = 0.03569; // calculated values double cachedPrice1a = 99.204505, cachedPrice2a = 99.687192; double cachedPrice1b = 98.943393, cachedPrice2b = 101.986794; double cachedYield1a = 0.029257, cachedYield2a = 0.035689; double cachedYield1b = 0.029045, cachedYield2b = 0.035375; double cachedYield1c = 0.030423, cachedYield2c = 0.030432; // check double tolerance = 1.0e-6; double price, yield; price = bond1.cleanPrice(marketYield1, bondDayCount, Compounding.Compounded, freq); if (Math.Abs(price - cachedPrice1a) > tolerance) { Assert.Fail("failed to reproduce cached price:" + "\n calculated: " + price + "\n expected: " + cachedPrice1a + "\n tolerance: " + tolerance + "\n error: " + (price - cachedPrice1a)); } price = bond1.cleanPrice(); if (Math.Abs(price - cachedPrice1b) > tolerance) { Assert.Fail("failed to reproduce cached price:" + "\n calculated: " + price + "\n expected: " + cachedPrice1b + "\n tolerance: " + tolerance + "\n error: " + (price - cachedPrice1b)); } yield = bond1.yield(marketPrice1, bondDayCount, Compounding.Compounded, freq); if (Math.Abs(yield - cachedYield1a) > tolerance) { Assert.Fail("failed to reproduce cached compounded yield:" + "\n calculated: " + yield + "\n expected: " + cachedYield1a + "\n tolerance: " + tolerance + "\n error: " + (yield - cachedYield1a)); } yield = bond1.yield(marketPrice1, bondDayCount, Compounding.Continuous, freq); if (Math.Abs(yield - cachedYield1b) > tolerance) { Assert.Fail("failed to reproduce cached continuous yield:" + "\n calculated: " + yield + "\n expected: " + cachedYield1b + "\n tolerance: " + tolerance + "\n error: " + (yield - cachedYield1b)); } yield = bond1.yield(bondDayCount, Compounding.Continuous, freq); if (Math.Abs(yield - cachedYield1c) > tolerance) { Assert.Fail("failed to reproduce cached continuous yield:" + "\n calculated: " + yield + "\n expected: " + cachedYield1c + "\n tolerance: " + tolerance + "\n error: " + (yield - cachedYield1c)); } price = bond2.cleanPrice(marketYield2, bondDayCount, Compounding.Compounded, freq); if (Math.Abs(price - cachedPrice2a) > tolerance) { Assert.Fail("failed to reproduce cached price:" + "\n calculated: " + price + "\n expected: " + cachedPrice2a + "\n tolerance: " + tolerance + "\n error: " + (price - cachedPrice2a)); } price = bond2.cleanPrice(); if (Math.Abs(price - cachedPrice2b) > tolerance) { Assert.Fail("failed to reproduce cached price:" + "\n calculated: " + price + "\n expected: " + cachedPrice2b + "\n tolerance: " + tolerance + "\n error: " + (price - cachedPrice2b)); } yield = bond2.yield(marketPrice2, bondDayCount, Compounding.Compounded, freq); if (Math.Abs(yield - cachedYield2a) > tolerance) { Assert.Fail("failed to reproduce cached compounded yield:" + "\n calculated: " + yield + "\n expected: " + cachedYield2a + "\n tolerance: " + tolerance + "\n error: " + (yield - cachedYield2a)); } yield = bond2.yield(marketPrice2, bondDayCount, Compounding.Continuous, freq); if (Math.Abs(yield - cachedYield2b) > tolerance) { Assert.Fail("failed to reproduce cached continuous yield:" + "\n calculated: " + yield + "\n expected: " + cachedYield2b + "\n tolerance: " + tolerance + "\n error: " + (yield - cachedYield2b)); } yield = bond2.yield(bondDayCount, Compounding.Continuous, freq); if (Math.Abs(yield - cachedYield2c) > tolerance) { Assert.Fail("failed to reproduce cached continuous yield:" + "\n calculated: " + yield + "\n expected: " + cachedYield2c + "\n tolerance: " + tolerance + "\n error: " + (yield - cachedYield2c)); } // with explicit settlement date: Schedule sch3 = new Schedule(new Date(30, Month.November, 2004), new Date(30, Month.November, 2006), new Period(freq), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBond bond3 = new FixedRateBond(settlementDays, vars.faceAmount, sch3, new List <double>() { 0.02875 }, new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, 100.0, new Date(30, Month.November, 2004)); bond3.setPricingEngine(bondEngine); double marketYield3 = 0.02997; Date settlementDate = new Date(30, Month.November, 2004); double cachedPrice3 = 99.764874; price = bond3.cleanPrice(marketYield3, bondDayCount, Compounding.Compounded, freq, settlementDate); if (Math.Abs(price - cachedPrice3) > tolerance) { Assert.Fail("failed to reproduce cached price:" + "\n calculated: " + price + "" + "\n expected: " + cachedPrice3 + "" + "\n error: " + (price - cachedPrice3)); } // this should give the same result since the issue date is the // earliest possible settlement date Settings.setEvaluationDate(new Date(22, Month.November, 2004)); price = bond3.cleanPrice(marketYield3, bondDayCount, Compounding.Compounded, freq); if (Math.Abs(price - cachedPrice3) > tolerance) { Assert.Fail("failed to reproduce cached price:" + "\n calculated: " + price + "" + "\n expected: " + cachedPrice3 + "" + "\n error: " + (price - cachedPrice3)); } }
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(); }
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(ActualActual obj) { return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr); }
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(); }
public void testActualActualWithSchedule() { // Testing actual/actual day counter with schedule // long first coupon Date issueDateExpected = new Date(17, Month.January, 2017); Date firstCouponDateExpected = new Date(31, Month.August, 2017); Schedule schedule = new MakeSchedule() .from(issueDateExpected) .withFirstDate(firstCouponDateExpected) .to(new Date(28, Month.February, 2026)) .withFrequency(Frequency.Semiannual) .withCalendar(new Canada()) .withConvention(BusinessDayConvention.Unadjusted) .backwards() .endOfMonth().value(); Date issueDate = schedule.date(0); Utils.QL_REQUIRE(issueDate == issueDateExpected, () => "This is not the expected issue date " + issueDate + " expected " + issueDateExpected); Date firstCouponDate = schedule.date(1); Utils.QL_REQUIRE(firstCouponDate == firstCouponDateExpected, () => "This is not the expected first coupon date " + firstCouponDate + " expected: " + firstCouponDateExpected); //Make thw quasi coupon dates: Date quasiCouponDate2 = schedule.calendar().advance(firstCouponDate, -schedule.tenor(), schedule.businessDayConvention(), schedule.endOfMonth()); Date quasiCouponDate1 = schedule.calendar().advance(quasiCouponDate2, -schedule.tenor(), schedule.businessDayConvention(), schedule.endOfMonth()); Date quasiCouponDate1Expected = new Date(31, Month.August, 2016); Date quasiCouponDate2Expected = new Date(28, Month.February, 2017); Utils.QL_REQUIRE(quasiCouponDate2 == quasiCouponDate2Expected, () => "Expected " + quasiCouponDate2Expected + " as the later quasi coupon date but received " + quasiCouponDate2); Utils.QL_REQUIRE(quasiCouponDate1 == quasiCouponDate1Expected, () => "Expected " + quasiCouponDate1Expected + " as the earlier quasi coupon date but received " + quasiCouponDate1); DayCounter dayCounter = new ActualActual(ActualActual.Convention.ISMA, schedule); // full coupon double t_with_reference = dayCounter.yearFraction( issueDate, firstCouponDate, quasiCouponDate2, firstCouponDate ); double t_no_reference = dayCounter.yearFraction( issueDate, firstCouponDate ); double t_total = ISMAYearFractionWithReferenceDates(dayCounter, issueDate, quasiCouponDate2, quasiCouponDate1, quasiCouponDate2) + 0.5; double expected = 0.6160220994; if (Math.Abs(t_total - expected) > 1.0e-10) { QAssert.Fail("Failed to reproduce expected time:\n" + " calculated: " + t_total + "\n" + " expected: " + expected); } if (Math.Abs(t_with_reference - expected) > 1.0e-10) { QAssert.Fail("Failed to reproduce expected time:\n" + " calculated: " + t_with_reference + "\n" + " expected: " + expected); } if (Math.Abs(t_no_reference - t_with_reference) > 1.0e-10) { QAssert.Fail("Should produce the same time whether or not references are present"); } // settlement date in the first quasi-period Date settlementDate = new Date(29, Month.January, 2017); t_with_reference = ISMAYearFractionWithReferenceDates( dayCounter, issueDate, settlementDate, quasiCouponDate1, quasiCouponDate2 ); t_no_reference = dayCounter.yearFraction(issueDate, settlementDate); double t_expected_first_qp = 0.03314917127071823; //12.0/362 if (Math.Abs(t_with_reference - t_expected_first_qp) > 1.0e-10) { QAssert.Fail("Failed to reproduce expected time:\n" + " calculated: " + t_no_reference + "\n" + " expected: " + t_expected_first_qp); } if (Math.Abs(t_no_reference - t_with_reference) > 1.0e-10) { QAssert.Fail("Should produce the same time whether or not references are present"); } double t2 = dayCounter.yearFraction(settlementDate, firstCouponDate); if (Math.Abs(t_expected_first_qp + t2 - expected) > 1.0e-10) { QAssert.Fail("Sum of quasiperiod2 split is not consistent"); } // settlement date in the second quasi-period settlementDate = new Date(29, Month.July, 2017); t_no_reference = dayCounter.yearFraction(issueDate, settlementDate); t_with_reference = ISMAYearFractionWithReferenceDates( dayCounter, issueDate, quasiCouponDate2, quasiCouponDate1, quasiCouponDate2 ) + ISMAYearFractionWithReferenceDates( dayCounter, quasiCouponDate2, settlementDate, quasiCouponDate2, firstCouponDate ); if (Math.Abs(t_no_reference - t_with_reference) > 1.0e-10) { QAssert.Fail("These two cases should be identical"); } t2 = dayCounter.yearFraction(settlementDate, firstCouponDate); if (Math.Abs(t_total - (t_no_reference + t2)) > 1.0e-10) { QAssert.Fail("Failed to reproduce expected time:\n" + " calculated: " + t_total + "\n" + " expected: " + t_no_reference + t2); } }
public void testActualActual() { SingleCase[] testCases = { // first example new SingleCase(ActualActual.Convention.ISDA, new Date(1, Month.November, 2003), new Date(1, Month.May, 2004), 0.497724380567), new SingleCase(ActualActual.Convention.ISMA, new Date(1, Month.November, 2003), new Date(1, Month.May, 2004), new Date(1, Month.November, 2003), new Date(1, Month.May, 2004), 0.500000000000), new SingleCase(ActualActual.Convention.AFB, new Date(1, Month.November, 2003), new Date(1, Month.May, 2004), 0.497267759563), // short first calculation period (first period) new SingleCase(ActualActual.Convention.ISDA, new Date(1, Month.February, 1999), new Date(1, Month.July, 1999), 0.410958904110), new SingleCase(ActualActual.Convention.ISMA, new Date(1, Month.February, 1999), new Date(1, Month.July, 1999), new Date(1, Month.July, 1998), new Date(1, Month.July, 1999), 0.410958904110), new SingleCase(ActualActual.Convention.AFB, new Date(1, Month.February, 1999), new Date(1, Month.July, 1999), 0.410958904110), // short first calculation period (second period) new SingleCase(ActualActual.Convention.ISDA, new Date(1, Month.July, 1999), new Date(1, Month.July, 2000), 1.001377348600), new SingleCase(ActualActual.Convention.ISMA, new Date(1, Month.July, 1999), new Date(1, Month.July, 2000), new Date(1, Month.July, 1999), new Date(1, Month.July, 2000), 1.000000000000), new SingleCase(ActualActual.Convention.AFB, new Date(1, Month.July, 1999), new Date(1, Month.July, 2000), 1.000000000000), // long first calculation period (first period) new SingleCase(ActualActual.Convention.ISDA, new Date(15, Month.August, 2002), new Date(15, Month.July, 2003), 0.915068493151), new SingleCase(ActualActual.Convention.ISMA, new Date(15, Month.August, 2002), new Date(15, Month.July, 2003), new Date(15, Month.January, 2003), new Date(15, Month.July, 2003), 0.915760869565), new SingleCase(ActualActual.Convention.AFB, new Date(15, Month.August, 2002), new Date(15, Month.July, 2003), 0.915068493151), // long first calculation period (second period) /* Warning: the ISDA case is in disagreement with mktc1198.pdf */ new SingleCase(ActualActual.Convention.ISDA, new Date(15, Month.July, 2003), new Date(15, Month.January, 2004), 0.504004790778), new SingleCase(ActualActual.Convention.ISMA, new Date(15, Month.July, 2003), new Date(15, Month.January, 2004), new Date(15, Month.July, 2003), new Date(15, Month.January, 2004), 0.500000000000), new SingleCase(ActualActual.Convention.AFB, new Date(15, Month.July, 2003), new Date(15, Month.January, 2004), 0.504109589041), // short final calculation period (penultimate period) new SingleCase(ActualActual.Convention.ISDA, new Date(30, Month.July, 1999), new Date(30, Month.January, 2000), 0.503892506924), new SingleCase(ActualActual.Convention.ISMA, new Date(30, Month.July, 1999), new Date(30, Month.January, 2000), new Date(30, Month.July, 1999), new Date(30, Month.January, 2000), 0.500000000000), new SingleCase(ActualActual.Convention.AFB, new Date(30, Month.July, 1999), new Date(30, Month.January, 2000), 0.504109589041), // short final calculation period (final period) new SingleCase(ActualActual.Convention.ISDA, new Date(30, Month.January, 2000), new Date(30, Month.June, 2000), 0.415300546448), new SingleCase(ActualActual.Convention.ISMA, new Date(30, Month.January, 2000), new Date(30, Month.June, 2000), new Date(30, Month.January, 2000), new Date(30, Month.July, 2000), 0.417582417582), new SingleCase(ActualActual.Convention.AFB, new Date(30, Month.January, 2000), new Date(30, Month.June, 2000), 0.41530054644) }; int n = testCases.Length; /// sizeof(SingleCase); for (int i = 0; i < n; i++) { ActualActual dayCounter = new ActualActual(testCases[i]._convention); Date d1 = testCases[i]._start; Date d2 = testCases[i]._end; Date rd1 = testCases[i]._refStart; Date rd2 = testCases[i]._refEnd; double calculated = dayCounter.yearFraction(d1, d2, rd1, rd2); if (Math.Abs(calculated - testCases[i]._result) > 1.0e-10) { QAssert.Fail(dayCounter.name() + "period: " + d1 + " to " + d2 + " calculated: " + calculated + " expected: " + testCases[i]._result); } } }
public SingleCase(ActualActual.Convention convention, Date start, Date end, double result) { _convention = convention; _start = start; _end = end; _refStart = new Date(); _refEnd = new Date(); _result = result; }
public void testCached() { // ("Testing bond price/yield calculation against cached values..."); CommonVars vars = new CommonVars(); // with implicit settlement calculation: Date today = new Date(22, Month.November, 2004); Settings.setEvaluationDate(today); Calendar bondCalendar = new NullCalendar(); DayCounter bondDayCount = new ActualActual(ActualActual.Convention.ISMA); int settlementDays = 1; var discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(today, new SimpleQuote(0.03), new Actual360())); // actual market values from the evaluation date Frequency freq = Frequency.Semiannual; Schedule sch1 = new Schedule(new Date(31, Month.October, 2004), new Date(31, Month.October, 2006), new Period(freq), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBond bond1 = new FixedRateBond(settlementDays, vars.faceAmount, sch1, new List<double>() { 0.025 }, bondDayCount, BusinessDayConvention.ModifiedFollowing, 100.0, new Date(1, Month.November, 2004)); IPricingEngine bondEngine = new DiscountingBondEngine(discountCurve); bond1.setPricingEngine(bondEngine); double marketPrice1 = 99.203125; double marketYield1 = 0.02925; Schedule sch2 = new Schedule(new Date(15, Month.November, 2004), new Date(15, Month.November, 2009), new Period(freq), bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBond bond2 = new FixedRateBond(settlementDays, vars.faceAmount, sch2, new List<double>() { 0.035 }, bondDayCount, BusinessDayConvention.ModifiedFollowing, 100.0, new Date(15, Month.November, 2004)); bond2.setPricingEngine(bondEngine); double marketPrice2 = 99.6875; double marketYield2 = 0.03569; // calculated values double cachedPrice1a = 99.204505, cachedPrice2a = 99.687192; double cachedPrice1b = 98.943393, cachedPrice2b = 101.986794; double cachedYield1a = 0.029257, cachedYield2a = 0.035689; double cachedYield1b = 0.029045, cachedYield2b = 0.035375; double cachedYield1c = 0.030423, cachedYield2c = 0.030432; // check double tolerance = 1.0e-6; double price, yield; price = bond1.cleanPrice(marketYield1, bondDayCount, Compounding.Compounded, freq); if (Math.Abs(price - cachedPrice1a) > tolerance) { Assert.Fail("failed to reproduce cached price:" + "\n calculated: " + price + "\n expected: " + cachedPrice1a + "\n tolerance: " + tolerance + "\n error: " + (price - cachedPrice1a)); } price = bond1.cleanPrice(); if (Math.Abs(price - cachedPrice1b) > tolerance) { Assert.Fail("failed to reproduce cached price:" + "\n calculated: " + price + "\n expected: " + cachedPrice1b + "\n tolerance: " + tolerance + "\n error: " + (price - cachedPrice1b)); } yield = bond1.yield(marketPrice1, bondDayCount, Compounding.Compounded, freq); if (Math.Abs(yield - cachedYield1a) > tolerance) { Assert.Fail("failed to reproduce cached compounded yield:" + "\n calculated: " + yield + "\n expected: " + cachedYield1a + "\n tolerance: " + tolerance + "\n error: " + (yield - cachedYield1a)); } yield = bond1.yield(marketPrice1, bondDayCount, Compounding.Continuous, freq); if (Math.Abs(yield - cachedYield1b) > tolerance) { Assert.Fail("failed to reproduce cached continuous yield:" + "\n calculated: " + yield + "\n expected: " + cachedYield1b + "\n tolerance: " + tolerance + "\n error: " + (yield - cachedYield1b)); } yield = bond1.yield(bondDayCount, Compounding.Continuous, freq); if (Math.Abs(yield - cachedYield1c) > tolerance) { Assert.Fail("failed to reproduce cached continuous yield:" + "\n calculated: " + yield + "\n expected: " + cachedYield1c + "\n tolerance: " + tolerance + "\n error: " + (yield - cachedYield1c)); } price = bond2.cleanPrice(marketYield2, bondDayCount, Compounding.Compounded, freq); if (Math.Abs(price - cachedPrice2a) > tolerance) { Assert.Fail("failed to reproduce cached price:" + "\n calculated: " + price + "\n expected: " + cachedPrice2a + "\n tolerance: " + tolerance + "\n error: " + (price - cachedPrice2a)); } price = bond2.cleanPrice(); if (Math.Abs(price - cachedPrice2b) > tolerance) { Assert.Fail("failed to reproduce cached price:" + "\n calculated: " + price + "\n expected: " + cachedPrice2b + "\n tolerance: " + tolerance + "\n error: " + (price - cachedPrice2b)); } yield = bond2.yield(marketPrice2, bondDayCount, Compounding.Compounded, freq); if (Math.Abs(yield - cachedYield2a) > tolerance) { Assert.Fail("failed to reproduce cached compounded yield:" + "\n calculated: " + yield + "\n expected: " + cachedYield2a + "\n tolerance: " + tolerance + "\n error: " + (yield - cachedYield2a)); } yield = bond2.yield(marketPrice2, bondDayCount, Compounding.Continuous, freq); if (Math.Abs(yield - cachedYield2b) > tolerance) { Assert.Fail("failed to reproduce cached continuous yield:" + "\n calculated: " + yield + "\n expected: " + cachedYield2b + "\n tolerance: " + tolerance + "\n error: " + (yield - cachedYield2b)); } yield = bond2.yield(bondDayCount, Compounding.Continuous, freq); if (Math.Abs(yield - cachedYield2c) > tolerance) { Assert.Fail("failed to reproduce cached continuous yield:" + "\n calculated: " + yield + "\n expected: " + cachedYield2c + "\n tolerance: " + tolerance + "\n error: " + (yield - cachedYield2c)); } // with explicit settlement date: Schedule sch3 = new Schedule(new Date(30, Month.November, 2004), new Date(30, Month.November, 2006), new Period(freq), new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); FixedRateBond bond3 = new FixedRateBond(settlementDays, vars.faceAmount, sch3, new List<double>() { 0.02875 }, new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, 100.0, new Date(30, Month.November, 2004)); bond3.setPricingEngine(bondEngine); double marketYield3 = 0.02997; Date settlementDate = new Date(30, Month.November, 2004); double cachedPrice3 = 99.764874; price = bond3.cleanPrice(marketYield3, bondDayCount, Compounding.Compounded, freq, settlementDate); if (Math.Abs(price - cachedPrice3) > tolerance) { Assert.Fail("failed to reproduce cached price:" + "\n calculated: " + price + "" + "\n expected: " + cachedPrice3 + "" + "\n error: " + (price - cachedPrice3)); } // this should give the same result since the issue date is the // earliest possible settlement date Settings.setEvaluationDate(new Date(22, Month.November, 2004)); price = bond3.cleanPrice(marketYield3, bondDayCount, Compounding.Compounded, freq); if (Math.Abs(price - cachedPrice3) > tolerance) { Assert.Fail("failed to reproduce cached price:" + "\n calculated: " + price + "" + "\n expected: " + cachedPrice3 + "" + "\n error: " + (price - cachedPrice3)); } }
// setup public CommonVars() { backup = new SavedSettings(); nominalUK = new RelinkableHandle <YieldTermStructure>(); cpiUK = new RelinkableHandle <ZeroInflationTermStructure>(); hcpi = new RelinkableHandle <ZeroInflationTermStructure>(); zciisD = new List <Date>(); zciisR = new List <double>(); hii = new RelinkableHandle <ZeroInflationIndex>(); nominals = new InitializedList <double>(1, 1000000); // option variables frequency = Frequency.Annual; // usual setup volatility = 0.01; length = 7; calendar = new UnitedKingdom(); convention = BusinessDayConvention.ModifiedFollowing; Date today = new Date(1, Month.June, 2010); evaluationDate = calendar.adjust(today); Settings.setEvaluationDate(evaluationDate); settlementDays = 0; fixingDays = 0; settlement = calendar.advance(today, settlementDays, TimeUnit.Days); startDate = settlement; dcZCIIS = new ActualActual(); dcNominal = new ActualActual(); // uk rpi index // fixing data Date from = new Date(1, Month.July, 2007); Date to = new Date(1, Month.June, 2010); Schedule rpiSchedule = new MakeSchedule().from(from).to(to) .withTenor(new Period(1, TimeUnit.Months)) .withCalendar(new UnitedKingdom()) .withConvention(BusinessDayConvention.ModifiedFollowing).value(); double[] fixData = { 206.1, 207.3, 208.0, 208.9, 209.7, 210.9, 209.8, 211.4, 212.1, 214.0, 215.1, 216.8, // 2008 216.5, 217.2, 218.4, 217.7, 216.0, 212.9, 210.1, 211.4, 211.3, 211.5, 212.8, 213.4, // 2009 213.4, 214.4, 215.3, 216.0, 216.6, 218.0, 217.9, 219.2, 220.7, 222.8, -999, -999, // 2010 -999 }; // link from cpi index to cpi TS bool interp = false;// this MUST be false because the observation lag is only 2 months // for ZCIIS; but not for contract if the contract uses a bigger lag. ii = new UKRPI(interp, hcpi); for (int i = 0; i < rpiSchedule.Count; i++) { ii.addFixing(rpiSchedule[i], fixData[i], true);// force overwrite in case multiple use } Datum[] nominalData = { new Datum(new Date(2, Month.June, 2010), 0.499997), new Datum(new Date(3, Month.June, 2010), 0.524992), new Datum(new Date(8, Month.June, 2010), 0.524974), new Datum(new Date(15, Month.June, 2010), 0.549942), new Datum(new Date(22, Month.June, 2010), 0.549913), new Datum(new Date(1, Month.July, 2010), 0.574864), new Datum(new Date(2, Month.August, 2010), 0.624668), new Datum(new Date(1, Month.September, 2010), 0.724338), new Datum(new Date(16, Month.September, 2010), 0.769461), new Datum(new Date(1, Month.December, 2010), 0.997501), //{ Date( 16, December, 2010), 0.838164 ), new Datum(new Date(17, Month.March, 2011), 0.916996), new Datum(new Date(16, Month.June, 2011), 0.984339), new Datum(new Date(22, Month.September, 2011), 1.06085), new Datum(new Date(22, Month.December, 2011), 1.141788), new Datum(new Date(1, Month.June, 2012), 1.504426), new Datum(new Date(3, Month.June, 2013), 1.92064), new Datum(new Date(2, Month.June, 2014), 2.290824), new Datum(new Date(1, Month.June, 2015), 2.614394), new Datum(new Date(1, Month.June, 2016), 2.887445), new Datum(new Date(1, Month.June, 2017), 3.122128), new Datum(new Date(1, Month.June, 2018), 3.322511), new Datum(new Date(3, Month.June, 2019), 3.483997), new Datum(new Date(1, Month.June, 2020), 3.616896), new Datum(new Date(1, Month.June, 2022), 3.8281), new Datum(new Date(2, Month.June, 2025), 4.0341), new Datum(new Date(3, Month.June, 2030), 4.070854), new Datum(new Date(1, Month.June, 2035), 4.023202), new Datum(new Date(1, Month.June, 2040), 3.954748), new Datum(new Date(1, Month.June, 2050), 3.870953), new Datum(new Date(1, Month.June, 2060), 3.85298), new Datum(new Date(2, Month.June, 2070), 3.757542), new Datum(new Date(3, Month.June, 2080), 3.651379) }; int nominalDataLength = 33 - 1; List <Date> nomD = new List <Date>(); List <double> nomR = new List <double>(); for (int i = 0; i < nominalDataLength; i++) { nomD.Add(nominalData[i].date); nomR.Add(nominalData[i].rate / 100.0); } YieldTermStructure nominalTS = new InterpolatedZeroCurve <Linear>(nomD, nomR, dcNominal); nominalUK.linkTo(nominalTS); // now build the zero inflation curve observationLag = new Period(2, TimeUnit.Months); contractObservationLag = new Period(3, TimeUnit.Months); contractObservationInterpolation = InterpolationType.Flat; Datum[] zciisData = { new Datum(new Date(1, Month.June, 2011), 3.087), new Datum(new Date(1, Month.June, 2012), 3.12), new Datum(new Date(1, Month.June, 2013), 3.059), new Datum(new Date(1, Month.June, 2014), 3.11), new Datum(new Date(1, Month.June, 2015), 3.15), new Datum(new Date(1, Month.June, 2016), 3.207), new Datum(new Date(1, Month.June, 2017), 3.253), new Datum(new Date(1, Month.June, 2018), 3.288), new Datum(new Date(1, Month.June, 2019), 3.314), new Datum(new Date(1, Month.June, 2020), 3.401), new Datum(new Date(1, Month.June, 2022), 3.458), new Datum(new Date(1, Month.June, 2025), 3.52), new Datum(new Date(1, Month.June, 2030), 3.655), new Datum(new Date(1, Month.June, 2035), 3.668), new Datum(new Date(1, Month.June, 2040), 3.695), new Datum(new Date(1, Month.June, 2050), 3.634), new Datum(new Date(1, Month.June, 2060), 3.629), }; zciisDataLength = 17; for (int i = 0; i < zciisDataLength; i++) { zciisD.Add(zciisData[i].date); zciisR.Add(zciisData[i].rate); } // now build the helpers ... List <BootstrapHelper <ZeroInflationTermStructure> > helpers = makeHelpers(zciisData, zciisDataLength, ii, observationLag, calendar, convention, dcZCIIS); // we can use historical or first ZCIIS for this // we know historical is WAY off market-implied, so use market implied flat. baseZeroRate = zciisData[0].rate / 100.0; PiecewiseZeroInflationCurve <Linear> pCPIts = new PiecewiseZeroInflationCurve <Linear>( evaluationDate, calendar, dcZCIIS, observationLag, ii.frequency(), ii.interpolated(), baseZeroRate, new Handle <YieldTermStructure>(nominalTS), helpers); pCPIts.recalculate(); cpiUK.linkTo(pCPIts); hii.linkTo(ii); // make sure that the index has the latest zero inflation term structure hcpi.linkTo(pCPIts); // cpi CF price surf data Period[] cfMat = { new Period(3, TimeUnit.Years), new Period(5, TimeUnit.Years), new Period(7, TimeUnit.Years), new Period(10, TimeUnit.Years), new Period(15, TimeUnit.Years), new Period(20, TimeUnit.Years), new Period(30, TimeUnit.Years) }; double[] cStrike = { 3, 4, 5, 6 }; double[] fStrike = { -1, 0, 1, 2 }; int ncStrikes = 4, nfStrikes = 4, ncfMaturities = 7; double[][] cPrice = { new double[4] { 227.6, 100.27, 38.8, 14.94 }, new double[4] { 345.32, 127.9, 40.59, 14.11 }, new double[4] { 477.95, 170.19, 50.62, 16.88 }, new double[4] { 757.81, 303.95, 107.62, 43.61 }, new double[4] { 1140.73, 481.89, 168.4, 63.65 }, new double[4] { 1537.6, 607.72, 172.27, 54.87 }, new double[4] { 2211.67, 839.24, 184.75, 45.03 } }; double[][] fPrice = { new double[4] { 15.62, 28.38, 53.61, 104.6 }, new double[4] { 21.45, 36.73, 66.66, 129.6 }, new double[4] { 24.45, 42.08, 77.04, 152.24 }, new double[4] { 39.25, 63.52, 109.2, 203.44 }, new double[4] { 36.82, 63.62, 116.97, 232.73 }, new double[4] { 39.7, 67.47, 121.79, 238.56 }, new double[4] { 41.48, 73.9, 139.75, 286.75 } }; // now load the data into vector and Matrix classes cStrikesUK = new List <double>(); fStrikesUK = new List <double>(); cfMaturitiesUK = new List <Period>(); for (int i = 0; i < ncStrikes; i++) { cStrikesUK.Add(cStrike[i]); } for (int i = 0; i < nfStrikes; i++) { fStrikesUK.Add(fStrike[i]); } for (int i = 0; i < ncfMaturities; i++) { cfMaturitiesUK.Add(cfMat[i]); } cPriceUK = new Matrix(ncStrikes, ncfMaturities); fPriceUK = new Matrix(nfStrikes, ncfMaturities); for (int i = 0; i < ncStrikes; i++) { for (int j = 0; j < ncfMaturities; j++) { (cPriceUK)[i, j] = cPrice[j][i] / 10000.0; } } for (int i = 0; i < nfStrikes; i++) { for (int j = 0; j < ncfMaturities; j++) { (fPriceUK)[i, j] = fPrice[j][i] / 10000.0; } } }
public void testActualActual() { SingleCase[] testCases = { // first example new SingleCase(ActualActual.Convention.ISDA, new Date(1,Month.November,2003), new Date(1,Month.May,2004), 0.497724380567), new SingleCase(ActualActual.Convention.ISMA, new Date(1,Month.November,2003), new Date(1,Month.May,2004), new Date(1,Month.November,2003), new Date(1,Month.May,2004), 0.500000000000), new SingleCase(ActualActual.Convention.AFB, new Date(1,Month.November,2003), new Date(1,Month.May,2004), 0.497267759563), // short first calculation period (first period) new SingleCase(ActualActual.Convention.ISDA, new Date(1,Month.February,1999), new Date(1,Month.July,1999), 0.410958904110), new SingleCase(ActualActual.Convention.ISMA, new Date(1,Month.February,1999), new Date(1,Month.July,1999), new Date(1,Month.July,1998), new Date(1,Month.July,1999), 0.410958904110), new SingleCase(ActualActual.Convention.AFB, new Date(1,Month.February,1999), new Date(1,Month.July,1999), 0.410958904110), // short first calculation period (second period) new SingleCase(ActualActual.Convention.ISDA, new Date(1,Month.July,1999), new Date(1,Month.July,2000), 1.001377348600), new SingleCase(ActualActual.Convention.ISMA, new Date(1,Month.July,1999), new Date(1,Month.July,2000), new Date(1,Month.July,1999), new Date(1,Month.July,2000), 1.000000000000), new SingleCase(ActualActual.Convention.AFB, new Date(1,Month.July,1999), new Date(1,Month.July,2000), 1.000000000000), // long first calculation period (first period) new SingleCase(ActualActual.Convention.ISDA, new Date(15,Month.August,2002), new Date(15,Month.July,2003), 0.915068493151), new SingleCase(ActualActual.Convention.ISMA, new Date(15,Month.August,2002), new Date(15,Month.July,2003), new Date(15,Month.January,2003), new Date(15,Month.July,2003), 0.915760869565), new SingleCase(ActualActual.Convention.AFB, new Date(15,Month.August,2002), new Date(15,Month.July,2003), 0.915068493151), // long first calculation period (second period) /* Warning: the ISDA case is in disagreement with mktc1198.pdf */ new SingleCase(ActualActual.Convention.ISDA, new Date(15,Month.July,2003), new Date(15,Month.January,2004), 0.504004790778), new SingleCase(ActualActual.Convention.ISMA, new Date(15,Month.July,2003), new Date(15,Month.January,2004), new Date(15,Month.July,2003), new Date(15,Month.January,2004), 0.500000000000), new SingleCase(ActualActual.Convention.AFB, new Date(15,Month.July,2003), new Date(15,Month.January,2004), 0.504109589041), // short final calculation period (penultimate period) new SingleCase(ActualActual.Convention.ISDA, new Date(30,Month.July,1999), new Date(30,Month.January,2000), 0.503892506924), new SingleCase(ActualActual.Convention.ISMA, new Date(30,Month.July,1999), new Date(30,Month.January,2000), new Date(30,Month.July,1999), new Date(30,Month.January,2000), 0.500000000000), new SingleCase(ActualActual.Convention.AFB, new Date(30,Month.July,1999), new Date(30,Month.January,2000), 0.504109589041), // short final calculation period (final period) new SingleCase(ActualActual.Convention.ISDA, new Date(30,Month.January,2000), new Date(30,Month.June,2000), 0.415300546448), new SingleCase(ActualActual.Convention.ISMA, new Date(30,Month.January,2000), new Date(30,Month.June,2000), new Date(30,Month.January,2000), new Date(30,Month.July,2000), 0.417582417582), new SingleCase(ActualActual.Convention.AFB, new Date(30,Month.January,2000), new Date(30,Month.June,2000), 0.41530054644) }; int n = testCases.Length; /// sizeof(SingleCase); for (int i = 0; i < n; i++) { ActualActual dayCounter = new ActualActual(testCases[i]._convention); Date d1 = testCases[i]._start; Date d2 = testCases[i]._end; Date rd1 = testCases[i]._refStart; Date rd2 = testCases[i]._refEnd; double calculated = dayCounter.yearFraction(d1, d2, rd1, rd2); if (Math.Abs(calculated - testCases[i]._result) > 1.0e-10) { Assert.Fail(dayCounter.Name + "period: " + d1 + " to " + d2 + " calculated: " + calculated + " expected: " + testCases[i]._result); } } }
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(); }
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(ActualActual obj) { return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr; }