// setup public CommonVars() { // data calendar = new TARGET(); settlementDays = 2; today = calendar.adjust(Date.Today); Settings.setEvaluationDate(today); settlement = calendar.advance(today, settlementDays, TimeUnit.Days); fixedLegConvention = BusinessDayConvention.Unadjusted; fixedLegFrequency = Frequency.Annual; fixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.European); bondSettlementDays = 3; bondDayCounter = new ActualActual(); bondConvention = BusinessDayConvention.Following; bondRedemption = 100.0; bmaFrequency = Frequency.Quarterly; bmaConvention = BusinessDayConvention.Following; bmaDayCounter = new ActualActual(); deposits = depositData.Length; fras = fraData.Length; swaps = swapData.Length; bonds = bondData.Length; bmas = bmaData.Length; // market elements rates = new List <SimpleQuote>(deposits + swaps); fraRates = new List <SimpleQuote>(fras); prices = new List <SimpleQuote>(bonds); fractions = new List <SimpleQuote>(bmas); for (int i = 0; i < deposits; i++) { rates.Add(new SimpleQuote(depositData[i].rate / 100)); } for (int i = 0; i < swaps; i++) { rates.Add(new SimpleQuote(swapData[i].rate / 100)); } for (int i = 0; i < fras; i++) { fraRates.Add(new SimpleQuote(fraData[i].rate / 100)); } for (int i = 0; i < bonds; i++) { prices.Add(new SimpleQuote(bondData[i].price)); } for (int i = 0; i < bmas; i++) { fractions.Add(new SimpleQuote(bmaData[i].rate / 100)); } // rate helpers instruments = new List <RateHelper>(deposits + swaps); fraHelpers = new List <RateHelper>(fras); bondHelpers = new List <RateHelper>(bonds); schedules = new List <Schedule>(bonds); bmaHelpers = new List <RateHelper>(bmas); IborIndex euribor6m = new Euribor6M(); for (int i = 0; i < deposits; i++) { Handle <Quote> r = new Handle <Quote>(rates[i]); instruments.Add(new DepositRateHelper(r, new Period(depositData[i].n, depositData[i].units), euribor6m.fixingDays(), calendar, euribor6m.businessDayConvention(), euribor6m.endOfMonth(), euribor6m.dayCounter())); } for (int i = 0; i < swaps; i++) { Handle <Quote> r = new Handle <Quote>(rates[i + deposits]); instruments.Add(new SwapRateHelper(r, new Period(swapData[i].n, swapData[i].units), calendar, fixedLegFrequency, fixedLegConvention, fixedLegDayCounter, euribor6m)); } Euribor3M euribor3m = new Euribor3M(); for (int i = 0; i < fras; i++) { Handle <Quote> r = new Handle <Quote>(fraRates[i]); fraHelpers.Add(new FraRateHelper(r, fraData[i].n, fraData[i].n + 3, euribor3m.fixingDays(), euribor3m.fixingCalendar(), euribor3m.businessDayConvention(), euribor3m.endOfMonth(), euribor3m.dayCounter())); } for (int i = 0; i < bonds; i++) { Handle <Quote> p = new Handle <Quote>(prices[i]); Date maturity = calendar.advance(today, bondData[i].n, bondData[i].units); Date issue = calendar.advance(maturity, -bondData[i].length, TimeUnit.Years); List <double> coupons = new List <double>() { bondData[i].coupon / 100.0 }; schedules.Add(new Schedule(issue, maturity, new Period(bondData[i].frequency), calendar, bondConvention, bondConvention, DateGeneration.Rule.Backward, false)); bondHelpers.Add(new FixedRateBondHelper(p, bondSettlementDays, bondRedemption, schedules[i], coupons, bondDayCounter, bondConvention, bondRedemption, issue)); } }
public void testBootstrap() { // Testing Eonia-swap curve building... CommonVars vars = new CommonVars(); List <RateHelper> eoniaHelpers = new List <RateHelper>(); List <RateHelper> swap3mHelpers = new List <RateHelper>(); IborIndex euribor3m = new Euribor3M(); Eonia eonia = new Eonia(); for (int i = 0; i < depositData.Length; i++) { double rate = 0.01 * depositData[i].rate; SimpleQuote simple = new SimpleQuote(rate); Handle <Quote> quote = new Handle <Quote>(simple); Period term = new Period(depositData[i].n, depositData[i].unit); RateHelper helper = new DepositRateHelper(quote, term, depositData[i].settlementDays, euribor3m.fixingCalendar(), euribor3m.businessDayConvention(), euribor3m.endOfMonth(), euribor3m.dayCounter()); if (term <= new Period(2, TimeUnit.Days)) { eoniaHelpers.Add(helper); } if (term <= new Period(3, TimeUnit.Months)) { swap3mHelpers.Add(helper); } } for (int i = 0; i < fraData.Length; i++) { double rate = 0.01 * fraData[i].rate; SimpleQuote simple = new SimpleQuote(rate); Handle <Quote> quote = new Handle <Quote>(simple); RateHelper helper = new FraRateHelper(quote, fraData[i].nExpiry, fraData[i].nMaturity, fraData[i].settlementDays, euribor3m.fixingCalendar(), euribor3m.businessDayConvention(), euribor3m.endOfMonth(), euribor3m.dayCounter()); swap3mHelpers.Add(helper); } for (int i = 0; i < eoniaSwapData.Length; i++) { double rate = 0.01 * eoniaSwapData[i].rate; SimpleQuote simple = new SimpleQuote(rate); Handle <Quote> quote = new Handle <Quote>(simple); Period term = new Period(eoniaSwapData[i].n, eoniaSwapData[i].unit); RateHelper helper = new OISRateHelper(eoniaSwapData[i].settlementDays, term, quote, eonia); eoniaHelpers.Add(helper); } for (int i = 0; i < swapData.Length; i++) { double rate = 0.01 * swapData[i].rate; SimpleQuote simple = new SimpleQuote(rate); Handle <Quote> quote = new Handle <Quote>(simple); Period tenor = new Period(swapData[i].nIndexUnits, swapData[i].indexUnit); Period term = new Period(swapData[i].nTermUnits, swapData[i].termUnit); RateHelper helper = new SwapRateHelper(quote, term, vars.calendar, vars.fixedSwapFrequency, vars.fixedSwapConvention, vars.fixedSwapDayCount, euribor3m); if (tenor == new Period(3, TimeUnit.Months)) { swap3mHelpers.Add(helper); } } PiecewiseYieldCurve <Discount, LogLinear> eoniaTS = new PiecewiseYieldCurve <Discount, LogLinear>(vars.today, eoniaHelpers, new Actual365Fixed()); PiecewiseYieldCurve <Discount, LogLinear> swapTS = new PiecewiseYieldCurve <Discount, LogLinear>(vars.today, swap3mHelpers, new Actual365Fixed()); vars.eoniaTermStructure.linkTo(eoniaTS); // test curve consistency double tolerance = 1.0e-10; for (int i = 0; i < eoniaSwapData.Length; i++) { double expected = eoniaSwapData[i].rate; Period term = new Period(eoniaSwapData[i].n, eoniaSwapData[i].unit); OvernightIndexedSwap swap = vars.makeSwap(term, 0.0, 0.0); double?calculated = 100.0 * swap.fairRate(); if (Math.Abs(expected - calculated.Value) > tolerance) { QAssert.Fail("curve inconsistency:\n" + " swap length: " + term + "\n" + " quoted rate: " + expected + "\n" + " calculated rate: " + calculated); } } }
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(); }