public void testCurveConsistency <T, I, B>(CommonVars vars, I interpolator, double tolerance) where T : ITraits <YieldTermStructure>, new() where I : IInterpolationFactory, new() where B : IBootStrap <PiecewiseYieldCurve>, new() { vars.termStructure = new PiecewiseYieldCurve <T, I, B>(vars.settlement, vars.instruments, new Actual360(), new List <Handle <Quote> >(), new List <Date>(), 1.0e-12, interpolator); RelinkableHandle <YieldTermStructure> curveHandle = new RelinkableHandle <YieldTermStructure>(); curveHandle.linkTo(vars.termStructure); // check deposits for (int i = 0; i < vars.deposits; i++) { Euribor index = new Euribor(new Period(vars.depositData[i].n, vars.depositData[i].units), curveHandle); double expectedRate = vars.depositData[i].rate / 100, estimatedRate = index.fixing(vars.today); QAssert.IsTrue(Math.Abs(expectedRate - estimatedRate) < tolerance, vars.depositData[i].n + " " + (vars.depositData[i].units == TimeUnit.Weeks ? "week(s)" : "month(s)") + " deposit:" + "\n estimated rate: " + estimatedRate + "\n expected rate: " + expectedRate); } // check swaps IborIndex euribor6m = new Euribor6M(curveHandle); for (int i = 0; i < vars.swaps; i++) { Period tenor = new Period(vars.swapData[i].n, vars.swapData[i].units); VanillaSwap swap = new MakeVanillaSwap(tenor, euribor6m, 0.0) .withEffectiveDate(vars.settlement) .withFixedLegDayCount(vars.fixedLegDayCounter) .withFixedLegTenor(new Period(vars.fixedLegFrequency)) .withFixedLegConvention(vars.fixedLegConvention) .withFixedLegTerminationDateConvention(vars.fixedLegConvention); double expectedRate = vars.swapData[i].rate / 100, estimatedRate = swap.fairRate(); double error = Math.Abs(expectedRate - estimatedRate); QAssert.IsTrue(error < tolerance, vars.swapData[i].n + " year(s) swap:\n" + "\n estimated rate: " + estimatedRate + "\n expected rate: " + expectedRate + "\n error: " + error + "\n tolerance: " + tolerance); } // check bonds vars.termStructure = new PiecewiseYieldCurve <T, I, B>(vars.settlement, vars.bondHelpers, new Actual360(), new List <Handle <Quote> >(), new List <Date>(), 1.0e-12, interpolator); curveHandle.linkTo(vars.termStructure); for (int i = 0; i < vars.bonds; i++) { Date maturity = vars.calendar.advance(vars.today, vars.bondData[i].n, vars.bondData[i].units); Date issue = vars.calendar.advance(maturity, -vars.bondData[i].length, TimeUnit.Years); List <double> coupons = new List <double>() { vars.bondData[i].coupon / 100.0 }; FixedRateBond bond = new FixedRateBond(vars.bondSettlementDays, 100.0, vars.schedules[i], coupons, vars.bondDayCounter, vars.bondConvention, vars.bondRedemption, issue); IPricingEngine bondEngine = new DiscountingBondEngine(curveHandle); bond.setPricingEngine(bondEngine); double expectedPrice = vars.bondData[i].price, estimatedPrice = bond.cleanPrice(); QAssert.IsTrue(Math.Abs(expectedPrice - estimatedPrice) < tolerance, i + 1 + " bond failure:" + "\n estimated price: " + estimatedPrice + "\n expected price: " + expectedPrice); } // check FRA vars.termStructure = new PiecewiseYieldCurve <T, I, B>(vars.settlement, vars.fraHelpers, new Actual360(), new List <Handle <Quote> >(), new List <Date>(), 1.0e-12, interpolator); curveHandle.linkTo(vars.termStructure); IborIndex euribor3m = new Euribor3M(curveHandle); for (int i = 0; i < vars.fras; i++) { Date start = vars.calendar.advance(vars.settlement, vars.fraData[i].n, vars.fraData[i].units, euribor3m.businessDayConvention(), euribor3m.endOfMonth()); Date end = vars.calendar.advance(start, 3, TimeUnit.Months, euribor3m.businessDayConvention(), euribor3m.endOfMonth()); ForwardRateAgreement fra = new ForwardRateAgreement(start, end, Position.Type.Long, vars.fraData[i].rate / 100, 100.0, euribor3m, curveHandle); double expectedRate = vars.fraData[i].rate / 100, estimatedRate = fra.forwardRate().rate(); QAssert.IsTrue(Math.Abs(expectedRate - estimatedRate) < tolerance, i + 1 + " FRA failure:" + "\n estimated rate: " + estimatedRate + "\n expected rate: " + expectedRate); } }
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(); }