void OptionletStripperTest::testSwitchStrike() { BOOST_TEST_MESSAGE("Testing switch strike level and recalibration of level " "in case of curve relinking..."); CommonVars vars; Settings::instance().evaluationDate() = Date(28, October, 2013); vars.setCapFloorTermVolSurface(); RelinkableHandle< YieldTermStructure > yieldTermStructure; yieldTermStructure.linkTo(boost::shared_ptr< FlatForward >( new FlatForward(0, vars.calendar, 0.03, vars.dayCounter))); shared_ptr< IborIndex > iborIndex(new Euribor6M(yieldTermStructure)); boost::shared_ptr< OptionletStripper1 > optionletStripper1( new OptionletStripper1(vars.capFloorVolSurface, iborIndex, Null< Rate >(), vars.accuracy)); #if defined(QL_USE_INDEXED_COUPON) Real expected = 0.02981258; #else Real expected = 0.02981223; #endif Real error = std::fabs(optionletStripper1->switchStrike() - expected); if (error > vars.tolerance) BOOST_FAIL("\nSwitchstrike not correctly computed: " << "\nexpected switch strike: " << io::rate(expected) << "\ncomputed switch strike: " << io::rate(optionletStripper1->switchStrike()) << "\nerror: " << io::rate(error) << "\ntolerance: " << io::rate(vars.tolerance)); yieldTermStructure.linkTo(boost::shared_ptr< FlatForward >( new FlatForward(0, vars.calendar, 0.05, vars.dayCounter))); #if defined(QL_USE_INDEXED_COUPON) expected = 0.0499381; #else expected = 0.0499371; #endif error = std::fabs(optionletStripper1->switchStrike() - expected); if (error > vars.tolerance) BOOST_FAIL("\nSwitchstrike not correctly computed: " << "\nexpected switch strike: " << io::rate(expected) << "\ncomputed switch strike: " << io::rate(optionletStripper1->switchStrike()) << "\nerror: " << io::rate(error) << "\ntolerance: " << io::rate(vars.tolerance)); }
void DefaultProbabilityCurveTest::testSingleInstrumentBootstrap() { BOOST_TEST_MESSAGE("Testing single-instrument curve bootstrap..."); Calendar calendar = TARGET(); Date today = Settings::instance().evaluationDate(); Integer settlementDays = 0; Real quote = 0.005; Period tenor = 2*Years; Frequency frequency = Quarterly; BusinessDayConvention convention = Following; DateGeneration::Rule rule = DateGeneration::TwentiethIMM; DayCounter dayCounter = Thirty360(); Real recoveryRate = 0.4; RelinkableHandle<YieldTermStructure> discountCurve; discountCurve.linkTo(boost::shared_ptr<YieldTermStructure>( new FlatForward(today,0.06,Actual360()))); std::vector<boost::shared_ptr<DefaultProbabilityHelper> > helpers(1); helpers[0] = boost::shared_ptr<DefaultProbabilityHelper>( new SpreadCdsHelper(quote, tenor, settlementDays, calendar, frequency, convention, rule, dayCounter, recoveryRate, discountCurve)); PiecewiseDefaultCurve<HazardRate,BackwardFlat> defaultCurve(today, helpers, dayCounter); defaultCurve.recalculate(); }
void TermStructureTest::testCreateWithNullUnderlying() { BOOST_TEST_MESSAGE( "Testing that a zero-spreaded curve can be created with " "a null underlying curve..."); CommonVars vars; Handle<Quote> spread(ext::shared_ptr<Quote>(new SimpleQuote(0.01))); RelinkableHandle<YieldTermStructure> underlying; // this shouldn't throw ext::shared_ptr<YieldTermStructure> spreaded( new ZeroSpreadedTermStructure(underlying,spread)); // if we do this, the curve can work. underlying.linkTo(vars.termStructure); // check that we can use it spreaded->referenceDate(); }
void TermStructureTest::testImpliedObs() { BOOST_TEST_MESSAGE("Testing observability of implied term structure..."); CommonVars vars; Date today = Settings::instance().evaluationDate(); Date newToday = today + 3*Years; Date newSettlement = vars.calendar.advance(newToday, vars.settlementDays,Days); RelinkableHandle<YieldTermStructure> h; ext::shared_ptr<YieldTermStructure> implied( new ImpliedTermStructure(h, newSettlement)); Flag flag; flag.registerWith(implied); h.linkTo(vars.termStructure); if (!flag.isUp()) BOOST_ERROR("Observer was not notified of term structure change"); }
void TermStructureTest::testFSpreadedObs() { BOOST_TEST_MESSAGE("Testing observability of forward-spreaded " "term structure..."); CommonVars vars; ext::shared_ptr<SimpleQuote> me(new SimpleQuote(0.01)); Handle<Quote> mh(me); RelinkableHandle<YieldTermStructure> h; //(vars.dummyTermStructure); ext::shared_ptr<YieldTermStructure> spreaded( new ForwardSpreadedTermStructure(h,mh)); Flag flag; flag.registerWith(spreaded); h.linkTo(vars.termStructure); if (!flag.isUp()) BOOST_ERROR("Observer was not notified of term structure change"); flag.lower(); me->setValue(0.005); if (!flag.isUp()) BOOST_ERROR("Observer was not notified of spread change"); }
void NthToDefaultTest::testGaussStudent() { BOOST_MESSAGE ("Testing nth-to-default against Hull-White values " "with Gaussian and Student copula..."); SavedSettings backup; /************************* * Tolerances */ Real relTolerance = 0.015; // relative difference Real absTolerance = 1; // absolute difference in bp Period timeUnit = 1*Weeks; // required to reach accuracy Size names = 10; QL_REQUIRE (LENGTH(hwDataDist) == names, "hwDataDist length does not match"); Real rate = 0.05; DayCounter dc = Actual365Fixed(); Compounding cmp = Continuous; // Simple; Real recovery = 0.4; vector<Real> lambda (names, 0.01); Schedule schedule = MakeSchedule().from(Date (1, September, 2006)) .to(Date (1, September, 2011)) .withTenor(3*Months) .withCalendar(TARGET()); Date asofDate(31, August, 2006); Settings::instance().evaluationDate() = asofDate; vector<Date> gridDates; gridDates.push_back (asofDate); gridDates.push_back (TARGET().advance (asofDate, Period (1, Years))); gridDates.push_back (TARGET().advance (asofDate, Period (5, Years))); gridDates.push_back (TARGET().advance (asofDate, Period (7, Years))); shared_ptr<YieldTermStructure> yieldPtr (new FlatForward (asofDate, rate, dc, cmp)); Handle<YieldTermStructure> yieldHandle (yieldPtr); vector<Handle<DefaultProbabilityTermStructure> > probabilities; Period maxTerm (10, Years); for (Size i = 0; i < lambda.size(); i++) { Handle<Quote> h(shared_ptr<Quote>(new SimpleQuote(lambda[i]))); shared_ptr<DefaultProbabilityTermStructure> ptr ( new FlatHazardRate(asofDate, h, dc)); probabilities.push_back(Handle<DefaultProbabilityTermStructure>(ptr)); } shared_ptr<SimpleQuote> simpleQuote (new SimpleQuote(0.3)); Handle<Quote> correlationHandle (simpleQuote); shared_ptr<OneFactorCopula> gaussianCopula ( new OneFactorGaussianCopula (correlationHandle)); shared_ptr<OneFactorCopula> studentCopula ( new OneFactorStudentCopula (correlationHandle, 5, 5)); RelinkableHandle<OneFactorCopula> copula; vector<NthToDefault> ntd; for (Size i = 1; i <= probabilities.size(); i++) ntd.push_back (NthToDefault (i, probabilities, recovery, copula, Protection::Seller, 100.0, schedule, 0.02, Actual360(), true, yieldHandle, timeUnit)); QL_REQUIRE (LENGTH(hwCorrelation) == 3, "correlation length does not match"); Real maxDiff = 0; simpleQuote->setValue (0.3); copula.linkTo (gaussianCopula); for (Size i = 0; i < ntd.size(); i++) { QL_REQUIRE (ntd[i].rank() == hwDataDist[i].rank, "rank does not match"); Real diff = 1e4 * ntd[i].fairPremium() - hwDataDist[i].spread[0]; maxDiff = max (maxDiff, fabs (diff)); BOOST_CHECK_MESSAGE (fabs(diff / hwDataDist[i].spread[0]) || fabs(diff) < absTolerance, "tolerance " << relTolerance << "|" << absTolerance << " exceeded"); } copula.linkTo (studentCopula); maxDiff = 0; for (Size i = 0; i < ntd.size(); i++) { QL_REQUIRE (ntd[i].rank() == hwDataDist[i].rank, "rank does not match"); Real diff = 1e4 * ntd[i].fairPremium() - hwDataDist[i].spread[3]; maxDiff = max (maxDiff, fabs (diff)); BOOST_CHECK_MESSAGE (fabs(diff / hwDataDist[i].spread[3]) || fabs(diff) < absTolerance, "tolerance " << relTolerance << "|" << absTolerance << " exceeded"); } }
void CreditDefaultSwapTest::testCachedValue() { BOOST_TEST_MESSAGE("Testing credit-default swap against cached values..."); SavedSettings backup; // Initialize curves Settings::instance().evaluationDate() = Date(9,June,2006); Date today = Settings::instance().evaluationDate(); Calendar calendar = TARGET(); Handle<Quote> hazardRate = Handle<Quote>( ext::shared_ptr<Quote>(new SimpleQuote(0.01234))); RelinkableHandle<DefaultProbabilityTermStructure> probabilityCurve; probabilityCurve.linkTo( ext::shared_ptr<DefaultProbabilityTermStructure>( new FlatHazardRate(0, calendar, hazardRate, Actual360()))); RelinkableHandle<YieldTermStructure> discountCurve; discountCurve.linkTo(ext::shared_ptr<YieldTermStructure>( new FlatForward(today,0.06,Actual360()))); // Build the schedule Date issueDate = calendar.advance(today, -1, Years); Date maturity = calendar.advance(issueDate, 10, Years); Frequency frequency = Semiannual; BusinessDayConvention convention = ModifiedFollowing; Schedule schedule(issueDate, maturity, Period(frequency), calendar, convention, convention, DateGeneration::Forward, false); // Build the CDS Rate fixedRate = 0.0120; DayCounter dayCount = Actual360(); Real notional = 10000.0; Real recoveryRate = 0.4; CreditDefaultSwap cds(Protection::Seller, notional, fixedRate, schedule, convention, dayCount, true, true); cds.setPricingEngine(ext::shared_ptr<PricingEngine>( new MidPointCdsEngine(probabilityCurve,recoveryRate,discountCurve))); Real npv = 295.0153398; Rate fairRate = 0.007517539081; Real calculatedNpv = cds.NPV(); Rate calculatedFairRate = cds.fairSpread(); Real tolerance = 1.0e-7; if (std::fabs(calculatedNpv - npv) > tolerance) BOOST_ERROR( "Failed to reproduce NPV with mid-point engine\n" << std::setprecision(10) << " calculated NPV: " << calculatedNpv << "\n" << " expected NPV: " << npv); if (std::fabs(calculatedFairRate - fairRate) > tolerance) BOOST_ERROR( "Failed to reproduce fair rate with mid-point engine\n" << std::setprecision(10) << " calculated fair rate: " << calculatedFairRate << "\n" << " expected fair rate: " << fairRate); cds.setPricingEngine(ext::shared_ptr<PricingEngine>( new IntegralCdsEngine(1*Days,probabilityCurve, recoveryRate,discountCurve))); calculatedNpv = cds.NPV(); calculatedFairRate = cds.fairSpread(); tolerance = 1.0e-5; if (std::fabs(calculatedNpv - npv) > notional*tolerance*10) BOOST_ERROR( "Failed to reproduce NPV with integral engine " "(step = 1 day)\n" << std::setprecision(10) << " calculated NPV: " << calculatedNpv << "\n" << " expected NPV: " << npv); if (std::fabs(calculatedFairRate - fairRate) > tolerance) BOOST_ERROR( "Failed to reproduce fair rate with integral engine " "(step = 1 day)\n" << std::setprecision(10) << " calculated fair rate: " << calculatedFairRate << "\n" << " expected fair rate: " << fairRate); cds.setPricingEngine(ext::shared_ptr<PricingEngine>( new IntegralCdsEngine(1*Weeks,probabilityCurve, recoveryRate,discountCurve))); calculatedNpv = cds.NPV(); calculatedFairRate = cds.fairSpread(); tolerance = 1.0e-5; if (std::fabs(calculatedNpv - npv) > notional*tolerance*10) BOOST_ERROR( "Failed to reproduce NPV with integral engine " "(step = 1 week)\n" << std::setprecision(10) << " calculated NPV: " << calculatedNpv << "\n" << " expected NPV: " << npv); if (std::fabs(calculatedFairRate - fairRate) > tolerance) BOOST_ERROR( "Failed to reproduce fair rate with integral engine " "(step = 1 week)\n" << std::setprecision(10) << " calculated fair rate: " << calculatedFairRate << "\n" << " expected fair rate: " << fairRate); }
void CreditDefaultSwapTest::testImpliedHazardRate() { BOOST_TEST_MESSAGE("Testing implied hazard-rate for credit-default swaps..."); SavedSettings backup; // Initialize curves Calendar calendar = TARGET(); Date today = calendar.adjust(Date::todaysDate()); Settings::instance().evaluationDate() = today; Rate h1 = 0.30, h2 = 0.40; DayCounter dayCounter = Actual365Fixed(); std::vector<Date> dates(3); std::vector<Real> hazardRates(3); dates[0] = today; hazardRates[0] = h1; dates[1] = today + 5*Years; hazardRates[1] = h1; dates[2] = today + 10*Years; hazardRates[2] = h2; RelinkableHandle<DefaultProbabilityTermStructure> probabilityCurve; probabilityCurve.linkTo(ext::shared_ptr<DefaultProbabilityTermStructure>( new InterpolatedHazardRateCurve<BackwardFlat>(dates, hazardRates, dayCounter))); RelinkableHandle<YieldTermStructure> discountCurve; discountCurve.linkTo(ext::shared_ptr<YieldTermStructure>( new FlatForward(today,0.03,Actual360()))); Frequency frequency = Semiannual; BusinessDayConvention convention = ModifiedFollowing; Date issueDate = calendar.advance(today, -6, Months); Rate fixedRate = 0.0120; DayCounter cdsDayCount = Actual360(); Real notional = 10000.0; Real recoveryRate = 0.4; Rate latestRate = Null<Rate>(); for (Integer n=6; n<=10; ++n) { Date maturity = calendar.advance(issueDate, n, Years); Schedule schedule(issueDate, maturity, Period(frequency), calendar, convention, convention, DateGeneration::Forward, false); CreditDefaultSwap cds(Protection::Seller, notional, fixedRate, schedule, convention, cdsDayCount, true, true); cds.setPricingEngine(ext::shared_ptr<PricingEngine>( new MidPointCdsEngine(probabilityCurve, recoveryRate, discountCurve))); Real NPV = cds.NPV(); Rate flatRate = cds.impliedHazardRate(NPV, discountCurve, dayCounter, recoveryRate); if (flatRate < h1 || flatRate > h2) { BOOST_ERROR("implied hazard rate outside expected range\n" << " maturity: " << n << " years\n" << " expected minimum: " << h1 << "\n" << " expected maximum: " << h2 << "\n" << " implied rate: " << flatRate); } if (n > 6 && flatRate < latestRate) { BOOST_ERROR("implied hazard rate decreasing with swap maturity\n" << " maturity: " << n << " years\n" << " previous rate: " << latestRate << "\n" << " implied rate: " << flatRate); } latestRate = flatRate; RelinkableHandle<DefaultProbabilityTermStructure> probability; probability.linkTo(ext::shared_ptr<DefaultProbabilityTermStructure>( new FlatHazardRate( today, Handle<Quote>(ext::shared_ptr<Quote>(new SimpleQuote(flatRate))), dayCounter))); CreditDefaultSwap cds2(Protection::Seller, notional, fixedRate, schedule, convention, cdsDayCount, true, true); cds2.setPricingEngine(ext::shared_ptr<PricingEngine>( new MidPointCdsEngine(probability,recoveryRate, discountCurve))); Real NPV2 = cds2.NPV(); Real tolerance = 1.0; if (std::fabs(NPV-NPV2) > tolerance) { BOOST_ERROR("failed to reproduce NPV with implied rate\n" << " expected: " << NPV << "\n" << " calculated: " << NPV2); } } }
int main(int, char* []) { try { boost::timer timer; std::cout << std::endl; /********************* *** MARKET DATA *** *********************/ RelinkableHandle<YieldTermStructure> euriborTermStructure; boost::shared_ptr<IborIndex> euribor3m( new Euribor3M(euriborTermStructure)); Date todaysDate = Date(23, May, 2006); Settings::instance().evaluationDate() = todaysDate; Calendar calendar = euribor3m->fixingCalendar(); Integer fixingDays = euribor3m->fixingDays(); Date settlementDate = calendar.advance(todaysDate, fixingDays, Days); std::cout << "Today: " << todaysDate.weekday() << ", " << todaysDate << std::endl; std::cout << "Settlement date: " << settlementDate.weekday() << ", " << settlementDate << std::endl; // 3 month term FRA quotes (index refers to monthsToStart) Rate threeMonthFraQuote[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 boost::shared_ptr<SimpleQuote> fra1x4Rate( new SimpleQuote(threeMonthFraQuote[1])); boost::shared_ptr<SimpleQuote> fra2x5Rate( new SimpleQuote(threeMonthFraQuote[2])); boost::shared_ptr<SimpleQuote> fra3x6Rate( new SimpleQuote(threeMonthFraQuote[3])); boost::shared_ptr<SimpleQuote> fra6x9Rate( new SimpleQuote(threeMonthFraQuote[6])); boost::shared_ptr<SimpleQuote> fra9x12Rate( new SimpleQuote(threeMonthFraQuote[9])); RelinkableHandle<Quote> h1x4; h1x4.linkTo(fra1x4Rate); RelinkableHandle<Quote> h2x5; h2x5.linkTo(fra2x5Rate); RelinkableHandle<Quote> h3x6; h3x6.linkTo(fra3x6Rate); RelinkableHandle<Quote> h6x9; h6x9.linkTo(fra6x9Rate); RelinkableHandle<Quote> h9x12; 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(); boost::shared_ptr<RateHelper> fra1x4( new FraRateHelper(h1x4, 1, 4, fixingDays, calendar, convention, endOfMonth, fraDayCounter)); boost::shared_ptr<RateHelper> fra2x5( new FraRateHelper(h2x5, 2, 5, fixingDays, calendar, convention, endOfMonth, fraDayCounter)); boost::shared_ptr<RateHelper> fra3x6( new FraRateHelper(h3x6, 3, 6, fixingDays, calendar, convention, endOfMonth, fraDayCounter)); boost::shared_ptr<RateHelper> fra6x9( new FraRateHelper(h6x9, 6, 9, fixingDays, calendar, convention, endOfMonth, fraDayCounter)); boost::shared_ptr<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 = ActualActual(ActualActual::ISDA); double tolerance = 1.0e-15; // A FRA curve std::vector<boost::shared_ptr<RateHelper> > fraInstruments; fraInstruments.push_back(fra1x4); fraInstruments.push_back(fra2x5); fraInstruments.push_back(fra3x6); fraInstruments.push_back(fra6x9); fraInstruments.push_back(fra9x12); boost::shared_ptr<YieldTermStructure> fraTermStructure( new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, fraInstruments, termStructureDayCounter, tolerance)); // Term structures used for pricing/discounting RelinkableHandle<YieldTermStructure> discountingTermStructure; discountingTermStructure.linkTo(fraTermStructure); /*********************** *** construct FRA's *** ***********************/ Calendar fraCalendar = euribor3m->fixingCalendar(); BusinessDayConvention fraBusinessDayConvention = euribor3m->businessDayConvention(); Position::Type fraFwdType = Position::Long; Real fraNotional = 100.0; const Integer FraTermMonths = 3; Integer monthsToStart[] = { 1, 2, 3, 6, 9 }; euriborTermStructure.linkTo(fraTermStructure); cout << endl; cout << "Test FRA construction, NPV calculation, and FRA purchase" << endl << endl; Size i; for (i=0; i<LENGTH(monthsToStart); i++) { Date fraValueDate = fraCalendar.advance( settlementDate,monthsToStart[i],Months, fraBusinessDayConvention); Date fraMaturityDate = fraCalendar.advance( fraValueDate,FraTermMonths,Months, fraBusinessDayConvention); Rate fraStrikeRate = threeMonthFraQuote[monthsToStart[i]]; ForwardRateAgreement myFRA(fraValueDate, fraMaturityDate, fraFwdType,fraStrikeRate, fraNotional, euribor3m, discountingTermStructure); cout << "3m Term FRA, Months to Start: " << monthsToStart[i] << endl; cout << "strike FRA rate: " << io::rate(fraStrikeRate) << endl; cout << "FRA 3m forward rate: " << myFRA.forwardRate() << endl; cout << "FRA market quote: " << io::rate(threeMonthFraQuote[monthsToStart[i]]) << endl; cout << "FRA spot value: " << myFRA.spotValue() << endl; cout << "FRA forward value: " << myFRA.forwardValue() << endl; cout << "FRA implied Yield: " << myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Simple, fraDayCounter) << endl; cout << "market Zero Rate: " << discountingTermStructure->zeroRate(fraMaturityDate, fraDayCounter, Simple) << endl; cout << "FRA NPV [should be zero]: " << myFRA.NPV() << endl << endl; } cout << endl << endl; cout << "Now take a 100 basis-point upward shift in FRA quotes " << "and examine NPV" << endl << endl; const Real 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<LENGTH(monthsToStart); i++) { Date fraValueDate = fraCalendar.advance( settlementDate,monthsToStart[i],Months, fraBusinessDayConvention); Date fraMaturityDate = fraCalendar.advance( fraValueDate,FraTermMonths,Months, fraBusinessDayConvention); Rate fraStrikeRate = threeMonthFraQuote[monthsToStart[i]] - BpsShift; ForwardRateAgreement myFRA(fraValueDate, fraMaturityDate, fraFwdType, fraStrikeRate, fraNotional, euribor3m, discountingTermStructure); cout << "3m Term FRA, 100 notional, Months to Start = " << monthsToStart[i] << endl; cout << "strike FRA rate: " << io::rate(fraStrikeRate) << endl; cout << "FRA 3m forward rate: " << myFRA.forwardRate() << endl; cout << "FRA market quote: " << io::rate(threeMonthFraQuote[monthsToStart[i]]) << endl; cout << "FRA spot value: " << myFRA.spotValue() << endl; cout << "FRA forward value: " << myFRA.forwardValue() << endl; cout << "FRA implied Yield: " << myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Simple, fraDayCounter) << endl; cout << "market Zero Rate: " << discountingTermStructure->zeroRate(fraMaturityDate, fraDayCounter, Simple) << endl; cout << "FRA NPV [should be positive]: " << myFRA.NPV() << endl << endl; } double seconds = timer.elapsed(); Integer hours = int(seconds/3600); seconds -= hours * 3600; Integer minutes = int(seconds/60); seconds -= minutes * 60; cout << " \nRun completed in "; if (hours > 0) cout << hours << " h "; if (hours > 0 || minutes > 0) cout << minutes << " m "; cout << fixed << setprecision(0) << seconds << " s\n" << endl; return 0; } catch (exception& e) { cerr << e.what() << endl; return 1; } catch (...) { cerr << "unknown error" << endl; return 1; } }
/*Market Data -> FRA Quote -> FRA rate helper -> Curve Building -> Construct FRA*/ int main(int, char* []) { try { boost::timer timer; std::cout << std::endl; std::ifstream file("data.csv"); CSVRow data_row; file >> data_row; const size_t num_data = data_row.size()/2; /********************* *** MARKET DATA *** *********************/ RelinkableHandle<YieldTermStructure> euriborTermStructure; boost::shared_ptr<IborIndex> euribor3m( new Euribor3M(euriborTermStructure)); Date todaysDate = Date(23, May, 2006); Settings::instance().evaluationDate() = todaysDate; Calendar calendar = euribor3m->fixingCalendar(); Integer fixingDays = euribor3m->fixingDays(); Date settlementDate = calendar.advance(todaysDate, fixingDays, Days); std::cout << "Today: " << todaysDate.weekday() << ", " << todaysDate << std::endl; std::cout << "Settlement date: " << settlementDate.weekday() << ", " << settlementDate << std::endl; // 3 month term FRA quotes (index refers to monthsToStart) vector <stFRAMarketData> vecMarketData; for(size_t i = 0 ; i < num_data; i++) { stFRAMarketData element_data; convertFromString(element_data.iMonthToStart, data_row[i]); element_data.iTermDuration = 3; //3 month term convertFromString(element_data.rateFraQuote, data_row[i + num_data]); vecMarketData.push_back(element_data); } /******************** *** 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 std::vector <boost::shared_ptr<SimpleQuote> > vecFRAQuote; for(size_t i = 0 ; i < num_data; i++) { boost::shared_ptr<SimpleQuote> fraRate(new SimpleQuote(vecMarketData[i].rateFraQuote)); vecFRAQuote.push_back(fraRate); } std::vector <RelinkableHandle<Quote> > vecQuoteHandle; for(size_t i = 0 ; i < num_data; i++) { RelinkableHandle<Quote> hQuote; hQuote.linkTo(vecFRAQuote[i]); vecQuoteHandle.push_back(hQuote); } /********************* *** 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(); std::vector < boost::shared_ptr<RateHelper> > vecRateHelper; for(size_t i = 0 ; i < num_data; i++) { boost::shared_ptr<RateHelper> fra_helper( new FraRateHelper(vecQuoteHandle[i],vecMarketData[i].iMonthToStart, vecMarketData[i].iMonthToStart + vecMarketData[i].iTermDuration, fixingDays, calendar, convention, endOfMonth, fraDayCounter)); vecRateHelper.push_back(fra_helper); } /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 DayCounter termStructureDayCounter = ActualActual(ActualActual::ISDA); double tolerance = 1.0e-15; // A FRA curve boost::shared_ptr<YieldTermStructure> fraTermStructure( new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, vecRateHelper, termStructureDayCounter, tolerance)); // Term structures used for pricing/discounting RelinkableHandle<YieldTermStructure> discountingTermStructure; discountingTermStructure.linkTo(fraTermStructure); /*********************** *** construct FRA's *** ***********************/ Calendar fraCalendar = euribor3m->fixingCalendar(); BusinessDayConvention fraBusinessDayConvention = euribor3m->businessDayConvention(); Position::Type fraFwdType = Position::Long; Real fraNotional = 100.0; //const Integer FraTermMonths = 3; //Integer monthsToStart[] = { 1, 2, 3, 6, 9 }; euriborTermStructure.linkTo(fraTermStructure); cout << endl; cout << "Test FRA construction, NPV calculation, and FRA purchase" << endl << endl; Size i; for (i=0; i < num_data; i++) { Date fraValueDate = fraCalendar.advance( settlementDate,vecMarketData[i].iMonthToStart, Months, fraBusinessDayConvention); Date fraMaturityDate = fraCalendar.advance( fraValueDate,vecMarketData[i].iTermDuration,Months, fraBusinessDayConvention); Rate fraStrikeRate = vecMarketData[i].rateFraQuote; ForwardRateAgreement myFRA(fraValueDate, fraMaturityDate, fraFwdType,fraStrikeRate, fraNotional, euribor3m, discountingTermStructure); cout << vecMarketData[i].iTermDuration<<"m Term FRA, Months to Start: " << vecMarketData[i].iMonthToStart << endl; cout << "strike FRA rate: " << io::rate(fraStrikeRate) << endl; cout << "FRA 3m forward rate: " << myFRA.forwardRate() << endl; cout << "FRA market quote: " << io::rate(vecMarketData[i].rateFraQuote) << endl; cout << "FRA spot value: " << myFRA.spotValue() << endl; cout << "FRA forward value: " << myFRA.forwardValue() << endl; cout << "FRA implied Yield: " << myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Simple, fraDayCounter) << endl; cout << "market Zero Rate: " << discountingTermStructure->zeroRate(fraMaturityDate, fraDayCounter, Simple) << endl; cout << "FRA NPV [should be zero]: " << myFRA.NPV() << endl << endl; } cout << endl << endl; cout << "Now take a 100 basis-point upward shift in FRA quotes " << "and examine NPV" << endl << endl; const Real BpsShift = 0.01; for(size_t i = 0; i< num_data; i++ ) { vecMarketData[i].rateFraQuote += BpsShift; vecFRAQuote[i]->setValue(vecMarketData[i].rateFraQuote); } for (i=0; i<num_data; i++) { Date fraValueDate = fraCalendar.advance( settlementDate,vecMarketData[i].iMonthToStart,Months, fraBusinessDayConvention); Date fraMaturityDate = fraCalendar.advance( fraValueDate,vecMarketData[i].iTermDuration,Months, fraBusinessDayConvention); Rate fraStrikeRate = vecMarketData[i].rateFraQuote - BpsShift; ForwardRateAgreement myFRA(fraValueDate, fraMaturityDate, fraFwdType, fraStrikeRate, fraNotional, euribor3m, discountingTermStructure); cout << vecMarketData[i].iTermDuration <<"m Term FRA, 100 notional, Months to Start = " << vecMarketData[i].iMonthToStart << endl; cout << "strike FRA rate: " << io::rate(fraStrikeRate) << endl; cout << "FRA 3m forward rate: " << myFRA.forwardRate() << endl; cout << "FRA market quote: " << io::rate(vecMarketData[i].rateFraQuote) << endl; cout << "FRA spot value: " << myFRA.spotValue() << endl; cout << "FRA forward value: " << myFRA.forwardValue() << endl; cout << "FRA implied Yield: " << myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Simple, fraDayCounter) << endl; cout << "market Zero Rate: " << discountingTermStructure->zeroRate(fraMaturityDate, fraDayCounter, Simple) << endl; cout << "FRA NPV [should be positive]: " << myFRA.NPV() << endl << endl; } Real seconds = timer.elapsed(); Integer hours = int(seconds/3600); seconds -= hours * 3600; Integer minutes = int(seconds/60); seconds -= minutes * 60; cout << " \nRun completed in "; if (hours > 0) cout << hours << " h "; if (hours > 0 || minutes > 0) cout << minutes << " m "; cout << fixed << setprecision(0) << seconds << " s\n" << endl; return 0; } catch (exception& e) { cerr << e.what() << endl; return 1; } catch (...) { cerr << "unknown error" << endl; return 1; } }
void CreditDefaultSwapTest::testCachedMarketValue() { BOOST_TEST_MESSAGE( "Testing credit-default swap against cached market values..."); SavedSettings backup; Settings::instance().evaluationDate() = Date(9,June,2006); Date evalDate = Settings::instance().evaluationDate(); Calendar calendar = UnitedStates(); std::vector<Date> discountDates; discountDates.push_back(evalDate); discountDates.push_back(calendar.advance(evalDate, 1, Weeks, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate, 1, Months, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate, 2, Months, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate, 3, Months, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate, 6, Months, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate,12, Months, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate, 2, Years, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate, 3, Years, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate, 4, Years, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate, 5, Years, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate, 6, Years, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate, 7, Years, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate, 8, Years, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate, 9, Years, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate,10, Years, ModifiedFollowing)); discountDates.push_back(calendar.advance(evalDate,15, Years, ModifiedFollowing)); std::vector<DiscountFactor> dfs; dfs.push_back(1.0); dfs.push_back(0.9990151375768731); dfs.push_back(0.99570502636871183); dfs.push_back(0.99118260474528685); dfs.push_back(0.98661167950906203); dfs.push_back(0.9732592953359388 ); dfs.push_back(0.94724424481038083); dfs.push_back(0.89844996737120875 ); dfs.push_back(0.85216647839921411 ); dfs.push_back(0.80775477692556874 ); dfs.push_back(0.76517289234200347 ); dfs.push_back(0.72401019553182933 ); dfs.push_back(0.68503909569219212 ); dfs.push_back(0.64797499814013748 ); dfs.push_back(0.61263171936255534 ); dfs.push_back(0.5791942350748791 ); dfs.push_back(0.43518868769953606 ); const DayCounter& curveDayCounter=Actual360(); RelinkableHandle<YieldTermStructure> discountCurve; discountCurve.linkTo( ext::shared_ptr<YieldTermStructure>( new DiscountCurve(discountDates, dfs, curveDayCounter))); DayCounter dayCounter = Thirty360(); std::vector<Date> dates; dates.push_back(evalDate); dates.push_back(calendar.advance(evalDate, 6, Months, ModifiedFollowing)); dates.push_back(calendar.advance(evalDate, 1, Years, ModifiedFollowing)); dates.push_back(calendar.advance(evalDate, 2, Years, ModifiedFollowing)); dates.push_back(calendar.advance(evalDate, 3, Years, ModifiedFollowing)); dates.push_back(calendar.advance(evalDate, 4, Years, ModifiedFollowing)); dates.push_back(calendar.advance(evalDate, 5, Years, ModifiedFollowing)); dates.push_back(calendar.advance(evalDate, 7, Years, ModifiedFollowing)); dates.push_back(calendar.advance(evalDate,10, Years, ModifiedFollowing)); std::vector<Probability> defaultProbabilities; defaultProbabilities.push_back(0.0000); defaultProbabilities.push_back(0.0047); defaultProbabilities.push_back(0.0093); defaultProbabilities.push_back(0.0286); defaultProbabilities.push_back(0.0619); defaultProbabilities.push_back(0.0953); defaultProbabilities.push_back(0.1508); defaultProbabilities.push_back(0.2288); defaultProbabilities.push_back(0.3666); std::vector<Real> hazardRates; hazardRates.push_back(0.0); for (Size i=1; i<dates.size(); ++i) { Time t1 = dayCounter.yearFraction(dates[0], dates[i-1]); Time t2 = dayCounter.yearFraction(dates[0], dates[i]); Probability S1 = 1.0 - defaultProbabilities[i-1]; Probability S2 = 1.0 - defaultProbabilities[i]; hazardRates.push_back(std::log(S1/S2)/(t2-t1)); } RelinkableHandle<DefaultProbabilityTermStructure> piecewiseFlatHazardRate; piecewiseFlatHazardRate.linkTo( ext::shared_ptr<DefaultProbabilityTermStructure>( new InterpolatedHazardRateCurve<BackwardFlat>(dates, hazardRates, Thirty360()))); // Testing credit default swap // Build the schedule Date issueDate(20, March, 2006); Date maturity(20, June, 2013); Frequency cdsFrequency = Semiannual; BusinessDayConvention cdsConvention = ModifiedFollowing; Schedule schedule(issueDate, maturity, Period(cdsFrequency), calendar, cdsConvention, cdsConvention, DateGeneration::Forward, false); // Build the CDS Real recoveryRate = 0.25; Rate fixedRate=0.0224; DayCounter dayCount=Actual360(); Real cdsNotional=100.0; CreditDefaultSwap cds(Protection::Seller, cdsNotional, fixedRate, schedule, cdsConvention, dayCount, true, true); cds.setPricingEngine(ext::shared_ptr<PricingEngine>( new MidPointCdsEngine(piecewiseFlatHazardRate, recoveryRate,discountCurve))); Real calculatedNpv = cds.NPV(); Real calculatedFairRate = cds.fairSpread(); double npv = -1.364048777; // from Bloomberg we have 98.15598868 - 100.00; double fairRate = 0.0248429452; // from Bloomberg we have 0.0258378; Real tolerance = 1e-9; if (std::fabs(npv - calculatedNpv) > tolerance) BOOST_ERROR( "Failed to reproduce the npv for the given credit-default swap\n" << std::setprecision(10) << " computed NPV: " << calculatedNpv << "\n" << " Given NPV: " << npv); if (std::fabs(fairRate - calculatedFairRate) > tolerance) BOOST_ERROR( "Failed to reproduce the fair rate for the given credit-default swap\n" << std::setprecision(10) << " computed fair rate: " << calculatedFairRate << "\n" << " Given fair rate: " << fairRate); }
void QtSwap::qtswap() { try { boost::timer timer; std::cout << std::endl; /********************* *** MARKET DATA *** *********************/ Calendar calendar = TARGET(); Date settlementDate(22, September, 2004); // must be a business day settlementDate = calendar.adjust(settlementDate); Integer fixingDays = 2; Date todaysDate = calendar.advance(settlementDate, -fixingDays, Days); // nothing to do with Date::todaysDate Settings::instance().evaluationDate() = todaysDate; todaysDate = Settings::instance().evaluationDate(); std::cout << "Today: " << todaysDate.weekday() << ", " << todaysDate << std::endl; std::cout << "Settlement date: " << settlementDate.weekday() << ", " << settlementDate << std::endl; // deposits Rate d1wQuote=0.0382; Rate d1mQuote=0.0372; Rate d3mQuote=0.0363; Rate d6mQuote=0.0353; Rate d9mQuote=0.0348; Rate d1yQuote=0.0345; // FRAs Rate fra3x6Quote=0.037125; Rate fra6x9Quote=0.037125; Rate fra6x12Quote=0.037125; // futures Real fut1Quote=96.2875; Real fut2Quote=96.7875; Real fut3Quote=96.9875; Real fut4Quote=96.6875; Real fut5Quote=96.4875; Real fut6Quote=96.3875; Real fut7Quote=96.2875; Real fut8Quote=96.0875; // swaps Rate s2yQuote=0.037125; Rate s3yQuote=0.0398; Rate s5yQuote=0.0443; Rate s10yQuote=0.05165; Rate 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 boost::shared_ptr<Quote> d1wRate(new SimpleQuote(d1wQuote)); boost::shared_ptr<Quote> d1mRate(new SimpleQuote(d1mQuote)); boost::shared_ptr<Quote> d3mRate(new SimpleQuote(d3mQuote)); boost::shared_ptr<Quote> d6mRate(new SimpleQuote(d6mQuote)); boost::shared_ptr<Quote> d9mRate(new SimpleQuote(d9mQuote)); boost::shared_ptr<Quote> d1yRate(new SimpleQuote(d1yQuote)); // FRAs boost::shared_ptr<Quote> fra3x6Rate(new SimpleQuote(fra3x6Quote)); boost::shared_ptr<Quote> fra6x9Rate(new SimpleQuote(fra6x9Quote)); boost::shared_ptr<Quote> fra6x12Rate(new SimpleQuote(fra6x12Quote)); // futures boost::shared_ptr<Quote> fut1Price(new SimpleQuote(fut1Quote)); boost::shared_ptr<Quote> fut2Price(new SimpleQuote(fut2Quote)); boost::shared_ptr<Quote> fut3Price(new SimpleQuote(fut3Quote)); boost::shared_ptr<Quote> fut4Price(new SimpleQuote(fut4Quote)); boost::shared_ptr<Quote> fut5Price(new SimpleQuote(fut5Quote)); boost::shared_ptr<Quote> fut6Price(new SimpleQuote(fut6Quote)); boost::shared_ptr<Quote> fut7Price(new SimpleQuote(fut7Quote)); boost::shared_ptr<Quote> fut8Price(new SimpleQuote(fut8Quote)); // swaps boost::shared_ptr<Quote> s2yRate(new SimpleQuote(s2yQuote)); boost::shared_ptr<Quote> s3yRate(new SimpleQuote(s3yQuote)); boost::shared_ptr<Quote> s5yRate(new SimpleQuote(s5yQuote)); boost::shared_ptr<Quote> s10yRate(new SimpleQuote(s10yQuote)); boost::shared_ptr<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 = Actual360(); boost::shared_ptr<RateHelper> d1w(new DepositRateHelper( Handle<Quote>(d1wRate), 1*Weeks, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d1m(new DepositRateHelper( Handle<Quote>(d1mRate), 1*Months, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d3m(new DepositRateHelper( Handle<Quote>(d3mRate), 3*Months, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d6m(new DepositRateHelper( Handle<Quote>(d6mRate), 6*Months, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d9m(new DepositRateHelper( Handle<Quote>(d9mRate), 9*Months, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d1y(new DepositRateHelper( Handle<Quote>(d1yRate), 1*Years, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); // setup FRAs boost::shared_ptr<RateHelper> fra3x6(new FraRateHelper( Handle<Quote>(fra3x6Rate), 3, 6, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> fra6x9(new FraRateHelper( Handle<Quote>(fra6x9Rate), 6, 9, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> fra6x12(new FraRateHelper( Handle<Quote>(fra6x12Rate), 6, 12, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); // setup futures // Rate convexityAdjustment = 0.0; Integer futMonths = 3; Date imm = IMM::nextDate(settlementDate); boost::shared_ptr<RateHelper> fut1(new FuturesRateHelper( Handle<Quote>(fut1Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut2(new FuturesRateHelper( Handle<Quote>(fut2Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut3(new FuturesRateHelper( Handle<Quote>(fut3Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut4(new FuturesRateHelper( Handle<Quote>(fut4Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut5(new FuturesRateHelper( Handle<Quote>(fut5Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut6(new FuturesRateHelper( Handle<Quote>(fut6Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut7(new FuturesRateHelper( Handle<Quote>(fut7Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut8(new FuturesRateHelper( Handle<Quote>(fut8Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); // setup swaps Frequency swFixedLegFrequency = Annual; BusinessDayConvention swFixedLegConvention = Unadjusted; DayCounter swFixedLegDayCounter = Thirty360(Thirty360::European); boost::shared_ptr<IborIndex> swFloatingLegIndex(new Euribor6M); boost::shared_ptr<RateHelper> s2y(new SwapRateHelper( Handle<Quote>(s2yRate), 2*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); boost::shared_ptr<RateHelper> s3y(new SwapRateHelper( Handle<Quote>(s3yRate), 3*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); boost::shared_ptr<RateHelper> s5y(new SwapRateHelper( Handle<Quote>(s5yRate), 5*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); boost::shared_ptr<RateHelper> s10y(new SwapRateHelper( Handle<Quote>(s10yRate), 10*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); boost::shared_ptr<RateHelper> s15y(new SwapRateHelper( Handle<Quote>(s15yRate), 15*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 DayCounter termStructureDayCounter = ActualActual(ActualActual::ISDA); double tolerance = 1.0e-15; // A depo-swap curve std::vector<boost::shared_ptr<RateHelper> > depoSwapInstruments; depoSwapInstruments.push_back(d1w); depoSwapInstruments.push_back(d1m); depoSwapInstruments.push_back(d3m); depoSwapInstruments.push_back(d6m); depoSwapInstruments.push_back(d9m); depoSwapInstruments.push_back(d1y); depoSwapInstruments.push_back(s2y); depoSwapInstruments.push_back(s3y); depoSwapInstruments.push_back(s5y); depoSwapInstruments.push_back(s10y); depoSwapInstruments.push_back(s15y); boost::shared_ptr<YieldTermStructure> depoSwapTermStructure( new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoSwapInstruments, termStructureDayCounter, tolerance)); // A depo-futures-swap curve std::vector<boost::shared_ptr<RateHelper> > depoFutSwapInstruments; depoFutSwapInstruments.push_back(d1w); depoFutSwapInstruments.push_back(d1m); depoFutSwapInstruments.push_back(fut1); depoFutSwapInstruments.push_back(fut2); depoFutSwapInstruments.push_back(fut3); depoFutSwapInstruments.push_back(fut4); depoFutSwapInstruments.push_back(fut5); depoFutSwapInstruments.push_back(fut6); depoFutSwapInstruments.push_back(fut7); depoFutSwapInstruments.push_back(fut8); depoFutSwapInstruments.push_back(s3y); depoFutSwapInstruments.push_back(s5y); depoFutSwapInstruments.push_back(s10y); depoFutSwapInstruments.push_back(s15y); boost::shared_ptr<YieldTermStructure> depoFutSwapTermStructure( new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoFutSwapInstruments, termStructureDayCounter, tolerance)); // A depo-FRA-swap curve std::vector<boost::shared_ptr<RateHelper> > depoFRASwapInstruments; depoFRASwapInstruments.push_back(d1w); depoFRASwapInstruments.push_back(d1m); depoFRASwapInstruments.push_back(d3m); depoFRASwapInstruments.push_back(fra3x6); depoFRASwapInstruments.push_back(fra6x9); depoFRASwapInstruments.push_back(fra6x12); depoFRASwapInstruments.push_back(s2y); depoFRASwapInstruments.push_back(s3y); depoFRASwapInstruments.push_back(s5y); depoFRASwapInstruments.push_back(s10y); depoFRASwapInstruments.push_back(s15y); boost::shared_ptr<YieldTermStructure> depoFRASwapTermStructure( new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoFRASwapInstruments, termStructureDayCounter, tolerance)); // Term structures that will be used for pricing: // the one used for discounting cash flows RelinkableHandle<YieldTermStructure> discountingTermStructure; // the one used for forward rate forecasting RelinkableHandle<YieldTermStructure> forecastingTermStructure; /********************* * SWAPS TO BE PRICED * **********************/ // constant nominal 1,000,000 Euro Real nominal = 1000000.0; // fixed leg Frequency fixedLegFrequency = Annual; BusinessDayConvention fixedLegConvention = Unadjusted; BusinessDayConvention floatingLegConvention = ModifiedFollowing; DayCounter fixedLegDayCounter = Thirty360(Thirty360::European); Rate fixedRate = 0.04; DayCounter floatingLegDayCounter = Actual360(); // floating leg Frequency floatingLegFrequency = Semiannual; boost::shared_ptr<IborIndex> euriborIndex( new Euribor6M(forecastingTermStructure)); Spread spread = 0.0; Integer lenghtInYears = 5; VanillaSwap::Type swapType = VanillaSwap::Payer; Date maturity = settlementDate + lenghtInYears*Years; Schedule fixedSchedule(settlementDate, maturity, Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration::Forward, false); Schedule floatSchedule(settlementDate, maturity, Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration::Forward, false); VanillaSwap spot5YearSwap(swapType, nominal, fixedSchedule, fixedRate, fixedLegDayCounter, floatSchedule, euriborIndex, spread, floatingLegDayCounter); Date fwdStart = calendar.advance(settlementDate, 1, Years); Date fwdMaturity = fwdStart + lenghtInYears*Years; Schedule fwdFixedSchedule(fwdStart, fwdMaturity, Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration::Forward, false); Schedule fwdFloatSchedule(fwdStart, fwdMaturity, Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration::Forward, false); VanillaSwap oneYearForward5YearSwap(swapType, nominal, fwdFixedSchedule, fixedRate, fixedLegDayCounter, fwdFloatSchedule, euriborIndex, spread, floatingLegDayCounter); /*************** * SWAP PRICING * ****************/ // utilities for reporting std::vector<std::string> headers(4); headers[0] = "term structure"; headers[1] = "net present value"; headers[2] = "fair spread"; headers[3] = "fair fixed rate"; std::string separator = " | "; Size width = headers[0].size() + separator.size() + headers[1].size() + separator.size() + headers[2].size() + separator.size() + headers[3].size() + separator.size() - 1; std::string rule(width, '-'), dblrule(width, '='); std::string tab(8, ' '); // calculations std::cout << dblrule << std::endl; std::cout << "5-year market swap-rate = " << std::setprecision(2) << io::rate(s5yRate->value()) << std::endl; std::cout << dblrule << std::endl; std::cout << tab << "5-years swap paying " << io::rate(fixedRate) << std::endl; std::cout << headers[0] << separator << headers[1] << separator << headers[2] << separator << headers[3] << separator << std::endl; std::cout << rule << std::endl; Real NPV; Rate fairRate; Spread fairSpread; boost::shared_ptr<PricingEngine> 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(); std::cout << std::setw(headers[0].size()) << "depo-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; // let's check that the 5 years swap has been correctly re-priced QL_REQUIRE(std::fabs(fairRate-s5yQuote)<1e-8, "5-years swap mispriced by " << io::rate(std::fabs(fairRate-s5yQuote))); forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-fut-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; QL_REQUIRE(std::fabs(fairRate-s5yQuote)<1e-8, "5-years swap mispriced!"); forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-FRA-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; QL_REQUIRE(std::fabs(fairRate-s5yQuote)<1e-8, "5-years swap mispriced!"); std::cout << rule << std::endl; // now let's price the 1Y forward 5Y swap std::cout << tab << "5-years, 1-year forward swap paying " << io::rate(fixedRate) << std::endl; std::cout << headers[0] << separator << headers[1] << separator << headers[2] << separator << headers[3] << separator << std::endl; std::cout << rule << std::endl; forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-fut-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-FRA-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; // 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. boost::shared_ptr<SimpleQuote> fiveYearsRate = boost::dynamic_pointer_cast<SimpleQuote>(s5yRate); fiveYearsRate->setValue(0.0460); std::cout << dblrule << std::endl; std::cout << "5-year market swap-rate = " << io::rate(s5yRate->value()) << std::endl; std::cout << dblrule << std::endl; std::cout << tab << "5-years swap paying " << io::rate(fixedRate) << std::endl; std::cout << headers[0] << separator << headers[1] << separator << headers[2] << separator << headers[3] << separator << std::endl; std::cout << rule << std::endl; // now get the updated results forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; QL_REQUIRE(std::fabs(fairRate-s5yRate->value())<1e-8, "5-years swap mispriced!"); forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-fut-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; QL_REQUIRE(std::fabs(fairRate-s5yRate->value())<1e-8, "5-years swap mispriced!"); forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = spot5YearSwap.NPV(); fairSpread = spot5YearSwap.fairSpread(); fairRate = spot5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-FRA-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; QL_REQUIRE(std::fabs(fairRate-s5yRate->value())<1e-8, "5-years swap mispriced!"); std::cout << rule << std::endl; // the 1Y forward 5Y swap changes as well std::cout << tab << "5-years, 1-year forward swap paying " << io::rate(fixedRate) << std::endl; std::cout << headers[0] << separator << headers[1] << separator << headers[2] << separator << headers[3] << separator << std::endl; std::cout << rule << std::endl; forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-fut-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); NPV = oneYearForward5YearSwap.NPV(); fairSpread = oneYearForward5YearSwap.fairSpread(); fairRate = oneYearForward5YearSwap.fairRate(); std::cout << std::setw(headers[0].size()) << "depo-FRA-swap" << separator; std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(2) << NPV << separator; std::cout << std::setw(headers[2].size()) << io::rate(fairSpread) << separator; std::cout << std::setw(headers[3].size()) << io::rate(fairRate) << separator; std::cout << std::endl; Real seconds = timer.elapsed(); Integer hours = int(seconds/3600); seconds -= hours * 3600; Integer minutes = int(seconds/60); seconds -= minutes * 60; std::cout << " \nRun completed in "; if (hours > 0) std::cout << hours << " h "; if (hours > 0 || minutes > 0) std::cout << minutes << " m "; std::cout << std::fixed << std::setprecision(0) << seconds << " s\n" << std::endl; } catch (std::exception& e) { std::cerr << e.what() << std::endl; } catch (...) { std::cerr << "unknown error" << std::endl; } }
void InflationTest::testYYTermStructure() { BOOST_MESSAGE("Testing year-on-year inflation term structure..."); SavedSettings backup; // try the YY UK Calendar calendar = UnitedKingdom(); BusinessDayConvention bdc = ModifiedFollowing; Date evaluationDate(13, August, 2007); evaluationDate = calendar.adjust(evaluationDate); Settings::instance().evaluationDate() = evaluationDate; // fixing data Date from(1, January, 2005); Date to(13, August, 2007); Schedule rpiSchedule = MakeSchedule().from(from).to(to) .withTenor(1*Months) .withCalendar(UnitedKingdom()) .withConvention(ModifiedFollowing); Real fixData[] = { 189.9, 189.9, 189.6, 190.5, 191.6, 192.0, 192.2, 192.2, 192.6, 193.1, 193.3, 193.6, 194.1, 193.4, 194.2, 195.0, 196.5, 197.7, 198.5, 198.5, 199.2, 200.1, 200.4, 201.1, 202.7, 201.6, 203.1, 204.4, 205.4, 206.2, 207.3, -999.0, -999 }; RelinkableHandle<YoYInflationTermStructure> hy; bool interp = false; boost::shared_ptr<YYUKRPIr> iir(new YYUKRPIr(interp, hy)); for (Size i=0; i<rpiSchedule.size();i++) { iir->addFixing(rpiSchedule[i], fixData[i]); } boost::shared_ptr<YieldTermStructure> nominalTS = nominalTermStructure(); // now build the YoY inflation curve Datum yyData[] = { { Date(13, August, 2008), 2.95 }, { Date(13, August, 2009), 2.95 }, { Date(13, August, 2010), 2.93 }, { Date(15, August, 2011), 2.955 }, { Date(13, August, 2012), 2.945 }, { Date(13, August, 2013), 2.985 }, { Date(13, August, 2014), 3.01 }, { Date(13, August, 2015), 3.035 }, { Date(13, August, 2016), 3.055 }, // note that { Date(13, August, 2017), 3.075 }, // some dates will be on { Date(13, August, 2019), 3.105 }, // holidays but the payment { Date(15, August, 2022), 3.135 }, // calendar will roll them { Date(13, August, 2027), 3.155 }, { Date(13, August, 2032), 3.145 }, { Date(13, August, 2037), 3.145 } }; Period observationLag = Period(2,Months); DayCounter dc = Thirty360(); // now build the helpers ... std::vector<boost::shared_ptr<BootstrapHelper<YoYInflationTermStructure> > > helpers = makeHelpers<YoYInflationTermStructure,YearOnYearInflationSwapHelper, YoYInflationIndex>(yyData, LENGTH(yyData), iir, observationLag, calendar, bdc, dc); Rate baseYYRate = yyData[0].rate/100.0; boost::shared_ptr<PiecewiseYoYInflationCurve<Linear> > pYYTS( new PiecewiseYoYInflationCurve<Linear>( evaluationDate, calendar, dc, observationLag, iir->frequency(),iir->interpolated(), baseYYRate, Handle<YieldTermStructure>(nominalTS), helpers)); pYYTS->recalculate(); // validation // yoy swaps should reprice to zero // yy rates should not equal yySwap rates Real eps = 0.000001; // usual swap engine Handle<YieldTermStructure> hTS(nominalTS); boost::shared_ptr<PricingEngine> sppe(new DiscountingSwapEngine(hTS)); // make sure that the index has the latest yoy term structure hy.linkTo(pYYTS); for (Size j = 1; j < LENGTH(yyData); j++) { from = nominalTS->referenceDate(); to = yyData[j].date; Schedule yoySchedule = MakeSchedule().from(from).to(to) .withConvention(Unadjusted) // fixed leg gets calendar from .withCalendar(calendar) // schedule .withTenor(1*Years) .backwards() ; YearOnYearInflationSwap yyS2(YearOnYearInflationSwap::Payer, 1000000.0, yoySchedule,//fixed schedule, but same as yoy yyData[j].rate/100.0, dc, yoySchedule, iir, observationLag, 0.0, //spread on index dc, UnitedKingdom()); yyS2.setPricingEngine(sppe); BOOST_CHECK_MESSAGE(fabs(yyS2.NPV())<eps,"fresh yoy swap NPV!=0 from TS " <<"swap quote for pt " << j << ", is " << yyData[j].rate/100.0 <<" vs YoY rate "<< pYYTS->yoyRate(yyData[j].date-observationLag) <<" at quote date "<<(yyData[j].date-observationLag) <<", NPV of a fresh yoy swap is " << yyS2.NPV() <<"\n fair rate " << yyS2.fairRate() <<" payment "<<yyS2.paymentConvention()); } Size jj=3; for (Size k = 0; k < 14; k++) { from = nominalTS->referenceDate() - k*Months; to = yyData[jj].date - k*Months; Schedule yoySchedule = MakeSchedule().from(from).to(to) .withConvention(Unadjusted) // fixed leg gets calendar from .withCalendar(calendar) // schedule .withTenor(1*Years) .backwards() ; YearOnYearInflationSwap yyS3(YearOnYearInflationSwap::Payer, 1000000.0, yoySchedule,//fixed schedule, but same as yoy yyData[jj].rate/100.0, dc, yoySchedule, iir, observationLag, 0.0, //spread on index dc, UnitedKingdom()); yyS3.setPricingEngine(sppe); BOOST_CHECK_MESSAGE(fabs(yyS3.NPV())< 20000.0, "unexpected size of aged YoY swap, aged " <<k<<" months: YY aged NPV = " << yyS3.NPV() <<", legs "<< yyS3.legNPV(0) << " and " << yyS3.legNPV(1) ); } }
void CreditDefaultSwapTest::testFairUpfront() { BOOST_TEST_MESSAGE( "Testing fair-upfront calculation for credit-default swaps..."); SavedSettings backup; // Initialize curves Calendar calendar = TARGET(); Date today = calendar.adjust(Date::todaysDate()); Settings::instance().evaluationDate() = today; Handle<Quote> hazardRate = Handle<Quote>( ext::shared_ptr<Quote>(new SimpleQuote(0.01234))); RelinkableHandle<DefaultProbabilityTermStructure> probabilityCurve; probabilityCurve.linkTo( ext::shared_ptr<DefaultProbabilityTermStructure>( new FlatHazardRate(0, calendar, hazardRate, Actual360()))); RelinkableHandle<YieldTermStructure> discountCurve; discountCurve.linkTo(ext::shared_ptr<YieldTermStructure>( new FlatForward(today,0.06,Actual360()))); // Build the schedule Date issueDate = today; Date maturity = calendar.advance(issueDate, 10, Years); BusinessDayConvention convention = Following; Schedule schedule = MakeSchedule().from(issueDate) .to(maturity) .withFrequency(Quarterly) .withCalendar(calendar) .withTerminationDateConvention(convention) .withRule(DateGeneration::TwentiethIMM); // Build the CDS Rate fixedRate = 0.05; Rate upfront = 0.001; DayCounter dayCount = Actual360(); Real notional = 10000.0; Real recoveryRate = 0.4; ext::shared_ptr<PricingEngine> engine( new MidPointCdsEngine(probabilityCurve, recoveryRate, discountCurve, true)); CreditDefaultSwap cds(Protection::Seller, notional, upfront, fixedRate, schedule, convention, dayCount, true, true); cds.setPricingEngine(engine); Rate fairUpfront = cds.fairUpfront(); CreditDefaultSwap fairCds(Protection::Seller, notional, fairUpfront, fixedRate, schedule, convention, dayCount, true, true); fairCds.setPricingEngine(engine); Real fairNPV = fairCds.NPV(); Real tolerance = 1e-10; if (std::fabs(fairNPV) > tolerance) BOOST_ERROR( "Failed to reproduce null NPV with calculated fair upfront\n" << " calculated upfront: " << io::rate(fairUpfront) << "\n" << " calculated NPV: " << fairNPV); // same with null upfront to begin with upfront = 0.0; CreditDefaultSwap cds2(Protection::Seller, notional, upfront, fixedRate, schedule, convention, dayCount, true, true); cds2.setPricingEngine(engine); fairUpfront = cds2.fairUpfront(); CreditDefaultSwap fairCds2(Protection::Seller, notional, fairUpfront, fixedRate, schedule, convention, dayCount, true, true); fairCds2.setPricingEngine(engine); fairNPV = fairCds2.NPV(); if (std::fabs(fairNPV) > tolerance) BOOST_ERROR( "Failed to reproduce null NPV with calculated fair upfront\n" << " calculated upfront: " << io::rate(fairUpfront) << "\n" << " calculated NPV: " << fairNPV); }
int main(int, char* []) { try { boost::timer timer; std::cout << std::endl; /********************* *** MARKET DATA *** *********************/ Calendar calendar = TARGET(); Date settlementDate(18, September, 2008); // must be a business day settlementDate = calendar.adjust(settlementDate); Integer fixingDays = 3; Natural settlementDays = 3; Date todaysDate = calendar.advance(settlementDate, -fixingDays, Days); // nothing to do with Date::todaysDate Settings::instance().evaluationDate() = todaysDate; std::cout << "Today: " << todaysDate.weekday() << ", " << todaysDate << std::endl; std::cout << "Settlement date: " << settlementDate.weekday() << ", " << settlementDate << std::endl; // 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 Rate zc3mQuote=0.0096; Rate zc6mQuote=0.0145; Rate zc1yQuote=0.0194; boost::shared_ptr<Quote> zc3mRate(new SimpleQuote(zc3mQuote)); boost::shared_ptr<Quote> zc6mRate(new SimpleQuote(zc6mQuote)); boost::shared_ptr<Quote> zc1yRate(new SimpleQuote(zc1yQuote)); DayCounter zcBondsDayCounter = Actual365Fixed(); boost::shared_ptr<RateHelper> zc3m(new DepositRateHelper( Handle<Quote>(zc3mRate), 3*Months, fixingDays, calendar, ModifiedFollowing, true, zcBondsDayCounter)); boost::shared_ptr<RateHelper> zc6m(new DepositRateHelper( Handle<Quote>(zc6mRate), 6*Months, fixingDays, calendar, ModifiedFollowing, true, zcBondsDayCounter)); boost::shared_ptr<RateHelper> zc1y(new DepositRateHelper( Handle<Quote>(zc1yRate), 1*Years, fixingDays, calendar, ModifiedFollowing, true, zcBondsDayCounter)); // setup bonds Real redemption = 100.0; const Size numberOfBonds = 5; Date issueDates[] = { Date (15, March, 2005), Date (15, June, 2005), Date (30, June, 2006), Date (15, November, 2002), Date (15, May, 1987) }; Date maturities[] = { Date (31, August, 2010), Date (31, August, 2011), Date (31, August, 2013), Date (15, August, 2018), Date (15, May, 2038) }; Real couponRates[] = { 0.02375, 0.04625, 0.03125, 0.04000, 0.04500 }; Real marketQuotes[] = { 100.390625, 106.21875, 100.59375, 101.6875, 102.140625 }; std::vector< boost::shared_ptr<SimpleQuote> > quote; for (Size i=0; i<numberOfBonds; i++) { boost::shared_ptr<SimpleQuote> cp(new SimpleQuote(marketQuotes[i])); quote.push_back(cp); } RelinkableHandle<Quote> quoteHandle[numberOfBonds]; for (Size i=0; i<numberOfBonds; i++) { quoteHandle[i].linkTo(quote[i]); } // Definition of the rate helpers std::vector<boost::shared_ptr<BondHelper> > bondsHelpers; for (Size i=0; i<numberOfBonds; i++) { Schedule schedule(issueDates[i], maturities[i], Period(Semiannual), UnitedStates(UnitedStates::GovernmentBond), Unadjusted, Unadjusted, DateGeneration::Backward, false); boost::shared_ptr<FixedRateBondHelper> bondHelper(new FixedRateBondHelper( quoteHandle[i], settlementDays, 100.0, schedule, std::vector<Rate>(1,couponRates[i]), ActualActual(ActualActual::Bond), Unadjusted, redemption, issueDates[i])); // the above could also be done by creating a // FixedRateBond instance and writing: // // boost::shared_ptr<BondHelper> bondHelper( // new BondHelper(quoteHandle[i], bond)); // // This would also work for bonds that still don't have a // specialized helper, such as floating-rate bonds. bondsHelpers.push_back(bondHelper); } /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 DayCounter termStructureDayCounter = ActualActual(ActualActual::ISDA); double tolerance = 1.0e-15; // A depo-bond curve std::vector<boost::shared_ptr<RateHelper> > bondInstruments; // Adding the ZC bonds to the curve for the short end bondInstruments.push_back(zc3m); bondInstruments.push_back(zc6m); bondInstruments.push_back(zc1y); // Adding the Fixed rate bonds to the curve for the long end for (Size i=0; i<numberOfBonds; i++) { bondInstruments.push_back(bondsHelpers[i]); } boost::shared_ptr<YieldTermStructure> bondDiscountingTermStructure( new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, bondInstruments, termStructureDayCounter, tolerance)); // Building of the Libor forecasting curve // deposits Rate d1wQuote=0.043375; Rate d1mQuote=0.031875; Rate d3mQuote=0.0320375; Rate d6mQuote=0.03385; Rate d9mQuote=0.0338125; Rate d1yQuote=0.0335125; // swaps Rate s2yQuote=0.0295; Rate s3yQuote=0.0323; Rate s5yQuote=0.0359; Rate s10yQuote=0.0412; Rate 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 boost::shared_ptr<Quote> d1wRate(new SimpleQuote(d1wQuote)); boost::shared_ptr<Quote> d1mRate(new SimpleQuote(d1mQuote)); boost::shared_ptr<Quote> d3mRate(new SimpleQuote(d3mQuote)); boost::shared_ptr<Quote> d6mRate(new SimpleQuote(d6mQuote)); boost::shared_ptr<Quote> d9mRate(new SimpleQuote(d9mQuote)); boost::shared_ptr<Quote> d1yRate(new SimpleQuote(d1yQuote)); // swaps boost::shared_ptr<Quote> s2yRate(new SimpleQuote(s2yQuote)); boost::shared_ptr<Quote> s3yRate(new SimpleQuote(s3yQuote)); boost::shared_ptr<Quote> s5yRate(new SimpleQuote(s5yQuote)); boost::shared_ptr<Quote> s10yRate(new SimpleQuote(s10yQuote)); boost::shared_ptr<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 = Actual360(); boost::shared_ptr<RateHelper> d1w(new DepositRateHelper( Handle<Quote>(d1wRate), 1*Weeks, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d1m(new DepositRateHelper( Handle<Quote>(d1mRate), 1*Months, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d3m(new DepositRateHelper( Handle<Quote>(d3mRate), 3*Months, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d6m(new DepositRateHelper( Handle<Quote>(d6mRate), 6*Months, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d9m(new DepositRateHelper( Handle<Quote>(d9mRate), 9*Months, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d1y(new DepositRateHelper( Handle<Quote>(d1yRate), 1*Years, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); // setup swaps Frequency swFixedLegFrequency = Annual; BusinessDayConvention swFixedLegConvention = Unadjusted; DayCounter swFixedLegDayCounter = Thirty360(Thirty360::European); boost::shared_ptr<IborIndex> swFloatingLegIndex(new Euribor6M); const Period forwardStart(1*Days); boost::shared_ptr<RateHelper> s2y(new SwapRateHelper( Handle<Quote>(s2yRate), 2*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, Handle<Quote>(),forwardStart)); boost::shared_ptr<RateHelper> s3y(new SwapRateHelper( Handle<Quote>(s3yRate), 3*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, Handle<Quote>(),forwardStart)); boost::shared_ptr<RateHelper> s5y(new SwapRateHelper( Handle<Quote>(s5yRate), 5*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, Handle<Quote>(),forwardStart)); boost::shared_ptr<RateHelper> s10y(new SwapRateHelper( Handle<Quote>(s10yRate), 10*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, Handle<Quote>(),forwardStart)); boost::shared_ptr<RateHelper> s15y(new SwapRateHelper( Handle<Quote>(s15yRate), 15*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex, Handle<Quote>(),forwardStart)); /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 // A depo-swap curve std::vector<boost::shared_ptr<RateHelper> > depoSwapInstruments; depoSwapInstruments.push_back(d1w); depoSwapInstruments.push_back(d1m); depoSwapInstruments.push_back(d3m); depoSwapInstruments.push_back(d6m); depoSwapInstruments.push_back(d9m); depoSwapInstruments.push_back(d1y); depoSwapInstruments.push_back(s2y); depoSwapInstruments.push_back(s3y); depoSwapInstruments.push_back(s5y); depoSwapInstruments.push_back(s10y); depoSwapInstruments.push_back(s15y); boost::shared_ptr<YieldTermStructure> depoSwapTermStructure( new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoSwapInstruments, termStructureDayCounter, tolerance)); // Term structures that will be used for pricing: // the one used for discounting cash flows RelinkableHandle<YieldTermStructure> discountingTermStructure; // the one used for forward rate forecasting RelinkableHandle<YieldTermStructure> forecastingTermStructure; /********************* * BONDS TO BE PRICED * **********************/ // Common data Real faceAmount = 100; // Pricing engine boost::shared_ptr<PricingEngine> bondEngine( new DiscountingBondEngine(discountingTermStructure)); // Zero coupon bond ZeroCouponBond zeroCouponBond( settlementDays, UnitedStates(UnitedStates::GovernmentBond), faceAmount, Date(15,August,2013), Following, Real(116.92), Date(15,August,2003)); zeroCouponBond.setPricingEngine(bondEngine); // Fixed 4.5% US Treasury Note Schedule fixedBondSchedule(Date(15, May, 2007), Date(15,May,2017), Period(Semiannual), UnitedStates(UnitedStates::GovernmentBond), Unadjusted, Unadjusted, DateGeneration::Backward, false); FixedRateBond fixedRateBond( settlementDays, faceAmount, fixedBondSchedule, std::vector<Rate>(1, 0.045), ActualActual(ActualActual::Bond), ModifiedFollowing, 100.0, Date(15, 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; const boost::shared_ptr<IborIndex> libor3m( new USDLibor(Period(3,Months),liborTermStructure)); libor3m->addFixing(Date(17, July, 2008),0.0278625); Schedule floatingBondSchedule(Date(21, October, 2005), Date(21, October, 2010), Period(Quarterly), UnitedStates(UnitedStates::NYSE), Unadjusted, Unadjusted, DateGeneration::Backward, true); FloatingRateBond floatingRateBond( settlementDays, faceAmount, floatingBondSchedule, libor3m, Actual360(), ModifiedFollowing, Natural(2), // Gearings std::vector<Real>(1, 1.0), // Spreads std::vector<Rate>(1, 0.001), // Caps std::vector<Rate>(), // Floors std::vector<Rate>(), // Fixing in arrears true, Real(100.0), Date(21, October, 2005)); floatingRateBond.setPricingEngine(bondEngine); // Coupon pricers boost::shared_ptr<IborCouponPricer> pricer(new BlackIborCouponPricer); // optionLet volatilities Volatility volatility = 0.0; Handle<OptionletVolatilityStructure> vol; vol = Handle<OptionletVolatilityStructure>( boost::shared_ptr<OptionletVolatilityStructure>(new ConstantOptionletVolatility( settlementDays, calendar, ModifiedFollowing, volatility, Actual365Fixed()))); pricer->setCapletVolatility(vol); 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 * ****************/ std::cout << std::endl; // write column headings Size widths[] = { 18, 10, 10, 10 }; std::cout << std::setw(widths[0]) << " " << std::setw(widths[1]) << "ZC" << std::setw(widths[2]) << "Fixed" << std::setw(widths[3]) << "Floating" << std::endl; std::string separator = " | "; Size width = widths[0] + widths[1] + widths[2] + widths[3]; std::string rule(width, '-'), dblrule(width, '='); std::string tab(8, ' '); std::cout << rule << std::endl; std::cout << std::fixed; std::cout << std::setprecision(2); std::cout << std::setw(widths[0]) << "Net present value" << std::setw(widths[1]) << zeroCouponBond.NPV() << std::setw(widths[2]) << fixedRateBond.NPV() << std::setw(widths[3]) << floatingRateBond.NPV() << std::endl; std::cout << std::setw(widths[0]) << "Clean price" << std::setw(widths[1]) << zeroCouponBond.cleanPrice() << std::setw(widths[2]) << fixedRateBond.cleanPrice() << std::setw(widths[3]) << floatingRateBond.cleanPrice() << std::endl; std::cout << std::setw(widths[0]) << "Dirty price" << std::setw(widths[1]) << zeroCouponBond.dirtyPrice() << std::setw(widths[2]) << fixedRateBond.dirtyPrice() << std::setw(widths[3]) << floatingRateBond.dirtyPrice() << std::endl; std::cout << std::setw(widths[0]) << "Accrued coupon" << std::setw(widths[1]) << zeroCouponBond.accruedAmount() << std::setw(widths[2]) << fixedRateBond.accruedAmount() << std::setw(widths[3]) << floatingRateBond.accruedAmount() << std::endl; std::cout << std::setw(widths[0]) << "Previous coupon" << std::setw(widths[1]) << "N/A" // zeroCouponBond << std::setw(widths[2]) << io::rate(fixedRateBond.previousCouponRate()) << std::setw(widths[3]) << io::rate(floatingRateBond.previousCouponRate()) << std::endl; std::cout << std::setw(widths[0]) << "Next coupon" << std::setw(widths[1]) << "N/A" // zeroCouponBond << std::setw(widths[2]) << io::rate(fixedRateBond.nextCouponRate()) << std::setw(widths[3]) << io::rate(floatingRateBond.nextCouponRate()) << std::endl; std::cout << std::setw(widths[0]) << "Yield" << std::setw(widths[1]) << io::rate(zeroCouponBond.yield(Actual360(),Compounded,Annual)) << std::setw(widths[2]) << io::rate(fixedRateBond.yield(Actual360(),Compounded,Annual)) << std::setw(widths[3]) << io::rate(floatingRateBond.yield(Actual360(),Compounded,Annual)) << std::endl; std::cout << std::endl; // Other computations std::cout << "Sample indirect computations (for the floating rate bond): " << std::endl; std::cout << rule << std::endl; std::cout << "Yield to Clean Price: " << floatingRateBond.cleanPrice(floatingRateBond.yield(Actual360(),Compounded,Annual),Actual360(),Compounded,Annual,settlementDate) << std::endl; std::cout << "Clean Price to Yield: " << io::rate(floatingRateBond.yield(floatingRateBond.cleanPrice(),Actual360(),Compounded,Annual,settlementDate)) << std::endl; /* "Yield to Price" "Price to Yield" */ double seconds = timer.elapsed(); Integer hours = int(seconds/3600); seconds -= hours * 3600; Integer minutes = int(seconds/60); seconds -= minutes * 60; std::cout << " \nRun completed in "; if (hours > 0) std::cout << hours << " h "; if (hours > 0 || minutes > 0) std::cout << minutes << " m "; std::cout << std::fixed << std::setprecision(0) << seconds << " s\n" << std::endl; return 0; } catch (std::exception& e) { std::cerr << e.what() << std::endl; return 1; } catch (...) { std::cerr << "unknown error" << std::endl; return 1; } }
void MainWindow::showSwapNPV() { //ui->lineEdit_SwapNPV->setText(tr("1000000000")); //ui->lineEdit_SwapFairRate->setText(QString::number(3.141659)); //ui->lineEdit_SwapFairSpread->setText(QString::number(2.68796451)); /********************* *** MARKET DATA *** *********************/ Calendar calendar = TARGET(); /////■ Date settlementDate(22, September, 2004); QDate qtFormSettlementDate = ui->dateEdit_settlementDate->date(); QuantLib::Date settlementDate(22, September, 2004); if(!qtFormSettlementDate.isNull() && qtFormSettlementDate.isValid()) { QuantLib::Date settlementDate_(qtFormSettlementDate.day(), (QuantLib::Month)(qtFormSettlementDate.month()), qtFormSettlementDate.year()); settlementDate = settlementDate_; } // must be a business day settlementDate = calendar.adjust(settlementDate); Integer fixingDays = 2; Date todaysDate = calendar.advance(settlementDate, -fixingDays, Days); // nothing to do with Date::todaysDate Settings::instance().evaluationDate() = todaysDate; todaysDate = Settings::instance().evaluationDate(); std::cout << "Today: " << todaysDate.weekday() << ", " << todaysDate << std::endl; std::cout << "Settlement date: " << settlementDate.weekday() << ", " << settlementDate << std::endl; // deposits Rate d1wQuote=0.0382; d1wQuote = static_cast<Rate>(ui->tableWidget_RatesDeposites->item(-1,1)->text().toDouble()*0.01); Rate d1mQuote=0.0372; d1mQuote = static_cast<Rate>(ui->tableWidget_RatesDeposites->item(0,1)->text().toDouble()*0.01); Rate d3mQuote=0.0363; d3mQuote = static_cast<Rate>(ui->tableWidget_RatesDeposites->item(1,1)->text().toDouble()*0.01); Rate d6mQuote=0.0353; d6mQuote = static_cast<Rate>(ui->tableWidget_RatesDeposites->item(2,1)->text().toDouble()*0.01); Rate d9mQuote=0.0348; d9mQuote = static_cast<Rate>(ui->tableWidget_RatesDeposites->item(3,1)->text().toDouble()*0.01); Rate d1yQuote=0.0345; d1yQuote = static_cast<Rate>(ui->tableWidget_RatesDeposites->item(4,1)->text().toDouble()*0.01); // FRAs Rate fra3x6Quote=0.037125; fra3x6Quote = static_cast<Rate>(ui->tableWidget_RatesFRAs->item(-1,1)->text().toDouble()*0.01); Rate fra6x9Quote=0.037125; fra6x9Quote = static_cast<Rate>(ui->tableWidget_RatesFRAs->item(0,1)->text().toDouble()*0.01); Rate fra6x12Quote=0.037125; fra6x12Quote = static_cast<Rate>(ui->tableWidget_RatesFRAs->item(1,1)->text().toDouble()*0.01); // futures Real fut1Quote=96.2875; fut1Quote = static_cast<Real>(ui->tableWidget_RatesFutures->item(-1,1)->text().toDouble()); Real fut2Quote=96.7875; fut2Quote = static_cast<Real>(ui->tableWidget_RatesFutures->item(0,1)->text().toDouble()); Real fut3Quote=96.9875; fut3Quote = static_cast<Real>(ui->tableWidget_RatesFutures->item(1,1)->text().toDouble()); Real fut4Quote=96.6875; fut4Quote = static_cast<Real>(ui->tableWidget_RatesFutures->item(2,1)->text().toDouble()); Real fut5Quote=96.4875; fut5Quote = static_cast<Real>(ui->tableWidget_RatesFutures->item(3,1)->text().toDouble()); Real fut6Quote=96.3875; fut6Quote = static_cast<Real>(ui->tableWidget_RatesFutures->item(4,1)->text().toDouble()); Real fut7Quote=96.2875; fut7Quote = static_cast<Real>(ui->tableWidget_RatesFutures->item(5,1)->text().toDouble()); Real fut8Quote=96.0875; fut8Quote = static_cast<Real>(ui->tableWidget_RatesFutures->item(6,1)->text().toDouble()); // swaps Rate s2yQuote=0.037125; s2yQuote = static_cast<Rate>(ui->tableWidget_RatesSwaps->item(-1,1)->text().toDouble()*0.01); Rate s3yQuote=0.0398; s3yQuote = static_cast<Rate>(ui->tableWidget_RatesSwaps->item(0,1)->text().toDouble()*0.01); Rate s5yQuote=0.0443; s5yQuote = static_cast<Rate>(ui->tableWidget_RatesSwaps->item(1,1)->text().toDouble()*0.01); Rate s10yQuote=0.05165; s10yQuote = static_cast<Rate>(ui->tableWidget_RatesSwaps->item(2,1)->text().toDouble()*0.01); Rate s15yQuote=0.055175; s15yQuote = static_cast<Rate>(ui->tableWidget_RatesSwaps->item(3,1)->text().toDouble()*0.01); /******************** *** 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 boost::shared_ptr<Quote> d1wRate(new SimpleQuote(d1wQuote)); boost::shared_ptr<Quote> d1mRate(new SimpleQuote(d1mQuote)); boost::shared_ptr<Quote> d3mRate(new SimpleQuote(d3mQuote)); boost::shared_ptr<Quote> d6mRate(new SimpleQuote(d6mQuote)); boost::shared_ptr<Quote> d9mRate(new SimpleQuote(d9mQuote)); boost::shared_ptr<Quote> d1yRate(new SimpleQuote(d1yQuote)); // FRAs boost::shared_ptr<Quote> fra3x6Rate(new SimpleQuote(fra3x6Quote)); boost::shared_ptr<Quote> fra6x9Rate(new SimpleQuote(fra6x9Quote)); boost::shared_ptr<Quote> fra6x12Rate(new SimpleQuote(fra6x12Quote)); // futures boost::shared_ptr<Quote> fut1Price(new SimpleQuote(fut1Quote)); boost::shared_ptr<Quote> fut2Price(new SimpleQuote(fut2Quote)); boost::shared_ptr<Quote> fut3Price(new SimpleQuote(fut3Quote)); boost::shared_ptr<Quote> fut4Price(new SimpleQuote(fut4Quote)); boost::shared_ptr<Quote> fut5Price(new SimpleQuote(fut5Quote)); boost::shared_ptr<Quote> fut6Price(new SimpleQuote(fut6Quote)); boost::shared_ptr<Quote> fut7Price(new SimpleQuote(fut7Quote)); boost::shared_ptr<Quote> fut8Price(new SimpleQuote(fut8Quote)); // swaps boost::shared_ptr<Quote> s2yRate(new SimpleQuote(s2yQuote)); boost::shared_ptr<Quote> s3yRate(new SimpleQuote(s3yQuote)); boost::shared_ptr<Quote> s5yRate(new SimpleQuote(s5yQuote)); boost::shared_ptr<Quote> s10yRate(new SimpleQuote(s10yQuote)); boost::shared_ptr<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 = Actual360(); boost::shared_ptr<RateHelper> d1w(new DepositRateHelper( Handle<Quote>(d1wRate), 1*Weeks, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d1m(new DepositRateHelper( Handle<Quote>(d1mRate), 1*Months, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d3m(new DepositRateHelper( Handle<Quote>(d3mRate), 3*Months, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d6m(new DepositRateHelper( Handle<Quote>(d6mRate), 6*Months, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d9m(new DepositRateHelper( Handle<Quote>(d9mRate), 9*Months, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> d1y(new DepositRateHelper( Handle<Quote>(d1yRate), 1*Years, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); // setup FRAs boost::shared_ptr<RateHelper> fra3x6(new FraRateHelper( Handle<Quote>(fra3x6Rate), 3, 6, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> fra6x9(new FraRateHelper( Handle<Quote>(fra6x9Rate), 6, 9, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); boost::shared_ptr<RateHelper> fra6x12(new FraRateHelper( Handle<Quote>(fra6x12Rate), 6, 12, fixingDays, calendar, ModifiedFollowing, true, depositDayCounter)); // setup futures // Rate convexityAdjustment = 0.0; Integer futMonths = 3; Date imm = IMM::nextDate(settlementDate); boost::shared_ptr<RateHelper> fut1(new FuturesRateHelper( Handle<Quote>(fut1Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut2(new FuturesRateHelper( Handle<Quote>(fut2Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut3(new FuturesRateHelper( Handle<Quote>(fut3Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut4(new FuturesRateHelper( Handle<Quote>(fut4Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut5(new FuturesRateHelper( Handle<Quote>(fut5Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut6(new FuturesRateHelper( Handle<Quote>(fut6Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut7(new FuturesRateHelper( Handle<Quote>(fut7Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); imm = IMM::nextDate(imm+1); boost::shared_ptr<RateHelper> fut8(new FuturesRateHelper( Handle<Quote>(fut8Price), imm, futMonths, calendar, ModifiedFollowing, true, depositDayCounter)); // setup swaps Frequency swFixedLegFrequency = Annual; BusinessDayConvention swFixedLegConvention = Unadjusted; DayCounter swFixedLegDayCounter = Thirty360(Thirty360::European); boost::shared_ptr<IborIndex> swFloatingLegIndex(new Euribor6M); boost::shared_ptr<RateHelper> s2y(new SwapRateHelper( Handle<Quote>(s2yRate), 2*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); boost::shared_ptr<RateHelper> s3y(new SwapRateHelper( Handle<Quote>(s3yRate), 3*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); boost::shared_ptr<RateHelper> s5y(new SwapRateHelper( Handle<Quote>(s5yRate), 5*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); boost::shared_ptr<RateHelper> s10y(new SwapRateHelper( Handle<Quote>(s10yRate), 10*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); boost::shared_ptr<RateHelper> s15y(new SwapRateHelper( Handle<Quote>(s15yRate), 15*Years, calendar, swFixedLegFrequency, swFixedLegConvention, swFixedLegDayCounter, swFloatingLegIndex)); /********************* ** CURVE BUILDING ** *********************/ // Any DayCounter would be fine. // ActualActual::ISDA ensures that 30 years is 30.0 DayCounter termStructureDayCounter = ActualActual(ActualActual::ISDA); double tolerance = 1.0e-15; // A depo-swap curve std::vector<boost::shared_ptr<RateHelper> > depoSwapInstruments; depoSwapInstruments.push_back(d1w); depoSwapInstruments.push_back(d1m); depoSwapInstruments.push_back(d3m); depoSwapInstruments.push_back(d6m); depoSwapInstruments.push_back(d9m); depoSwapInstruments.push_back(d1y); depoSwapInstruments.push_back(s2y); depoSwapInstruments.push_back(s3y); depoSwapInstruments.push_back(s5y); depoSwapInstruments.push_back(s10y); depoSwapInstruments.push_back(s15y); boost::shared_ptr<YieldTermStructure> depoSwapTermStructure( new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoSwapInstruments, termStructureDayCounter, tolerance)); // A depo-futures-swap curve std::vector<boost::shared_ptr<RateHelper> > depoFutSwapInstruments; depoFutSwapInstruments.push_back(d1w); depoFutSwapInstruments.push_back(d1m); depoFutSwapInstruments.push_back(fut1); depoFutSwapInstruments.push_back(fut2); depoFutSwapInstruments.push_back(fut3); depoFutSwapInstruments.push_back(fut4); depoFutSwapInstruments.push_back(fut5); depoFutSwapInstruments.push_back(fut6); depoFutSwapInstruments.push_back(fut7); depoFutSwapInstruments.push_back(fut8); depoFutSwapInstruments.push_back(s3y); depoFutSwapInstruments.push_back(s5y); depoFutSwapInstruments.push_back(s10y); depoFutSwapInstruments.push_back(s15y); boost::shared_ptr<YieldTermStructure> depoFutSwapTermStructure( new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoFutSwapInstruments, termStructureDayCounter, tolerance)); // A depo-FRA-swap curve std::vector<boost::shared_ptr<RateHelper> > depoFRASwapInstruments; depoFRASwapInstruments.push_back(d1w); depoFRASwapInstruments.push_back(d1m); depoFRASwapInstruments.push_back(d3m); depoFRASwapInstruments.push_back(fra3x6); depoFRASwapInstruments.push_back(fra6x9); depoFRASwapInstruments.push_back(fra6x12); depoFRASwapInstruments.push_back(s2y); depoFRASwapInstruments.push_back(s3y); depoFRASwapInstruments.push_back(s5y); depoFRASwapInstruments.push_back(s10y); depoFRASwapInstruments.push_back(s15y); boost::shared_ptr<YieldTermStructure> depoFRASwapTermStructure( new PiecewiseYieldCurve<Discount,LogLinear>( settlementDate, depoFRASwapInstruments, termStructureDayCounter, tolerance)); // Term structures that will be used for pricing: // the one used for discounting cash flows RelinkableHandle<YieldTermStructure> discountingTermStructure; // the one used for forward rate forecasting RelinkableHandle<YieldTermStructure> forecastingTermStructure; /********************* * SWAPS TO BE PRICED * **********************/ // constant nominal 1,000,000 Euro /////■ Real nominal = 1000000.0; Real nominal = static_cast<Real>(ui->doubleSpinBox_Notional->value()); // fixed leg /////■ Frequency fixedLegFrequency = Annual; Frequency fixedLegFrequency = Annual; /////■ BusinessDayConvention fixedLegConvention = Unadjusted; BusinessDayConvention fixedLegConvention = Unadjusted; /////■ DayCounter fixedLegDayCounter = Thirty360(Thirty360::European); DayCounter fixedLegDayCounter = Thirty360(Thirty360::European); /////■ Rate fixedRate = 0.04; Rate fixedRate = static_cast<Real>((ui->doubleSpinBox_fixedRate->value())*0.01); // floating leg /////■ Frequency floatingLegFrequency = Semiannual; Frequency floatingLegFrequency = Semiannual; int comboBoxFloatingLegFrequency = ui->comboBox_FloatingLegFrequency->currentIndex(); switch(comboBoxFloatingLegFrequency) { case 0: // Semiannual floatingLegFrequency = Semiannual; break; case 1: // Annual floatingLegFrequency = Annual; break; case 2: // Quarterly floatingLegFrequency = Quarterly; break; } /////■ BusinessDayConvention floatingLegConvention = ModifiedFollowing; BusinessDayConvention floatingLegConvention = ModifiedFollowing; /////■ DayCounter floatingLegDayCounter = Actual360(); DayCounter floatingLegDayCounter = Actual360(); boost::shared_ptr<IborIndex> euriborIndex( new Euribor6M(forecastingTermStructure)); /////■ Spread spread = 0.0; Spread spread = static_cast<Spread>((ui->doubleSpinBox_spread->value())*0.01); /////■ Integer lenghtInYears = 5; Integer lenghtInYears = (Integer)(ui->doubleSpinBox_lenghtInYears->value()); /////■ VanillaSwap::Type swapType = VanillaSwap::Payer; int comboBoxPayerReceiver = ui->comboBox_swapType->currentIndex(); VanillaSwap::Type swapType = VanillaSwap::Receiver; switch(comboBoxPayerReceiver) { case 0: // Fix Payer swapType = VanillaSwap::Payer; break; // VanillaSwap::Payer=1 case 1: // Fix Receiver swapType = VanillaSwap::Receiver; break; // VanillaSwap::Receiver=-1 } Date maturity = settlementDate + lenghtInYears*Years; Schedule fixedSchedule(settlementDate, maturity, Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration::Forward, false); Schedule floatSchedule(settlementDate, maturity, Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration::Forward, false); VanillaSwap spot5YearSwap(swapType, nominal, fixedSchedule, fixedRate, fixedLegDayCounter, floatSchedule, euriborIndex, spread, floatingLegDayCounter); Date fwdStart = calendar.advance(settlementDate, 1, Years); Date fwdMaturity = fwdStart + lenghtInYears*Years; Schedule fwdFixedSchedule(fwdStart, fwdMaturity, Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration::Forward, false); Schedule fwdFloatSchedule(fwdStart, fwdMaturity, Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration::Forward, false); VanillaSwap oneYearForward5YearSwap(swapType, nominal, fwdFixedSchedule, fixedRate, fixedLegDayCounter, fwdFloatSchedule, euriborIndex, spread, floatingLegDayCounter); /*************** * SWAP PRICING * ****************/ Real NPV; Rate fairRate; Spread fairSpread; boost::shared_ptr<PricingEngine> swapEngine( new DiscountingSwapEngine(discountingTermStructure)); spot5YearSwap.setPricingEngine(swapEngine); oneYearForward5YearSwap.setPricingEngine(swapEngine); int swapTermStructureType(0); swapTermStructureType = ui->comboBox_TermStructureType->currentIndex(); //QMessageBox msgBoxTmp(this); msgBoxTmp.setText(QString::number(swapTermStructureType)); msgBoxTmp.exec(); switch(swapTermStructureType) { case 0: forecastingTermStructure.linkTo(depoSwapTermStructure); discountingTermStructure.linkTo(depoSwapTermStructure); break; case 1: forecastingTermStructure.linkTo(depoFutSwapTermStructure); discountingTermStructure.linkTo(depoFutSwapTermStructure); break; case 2: forecastingTermStructure.linkTo(depoFRASwapTermStructure); discountingTermStructure.linkTo(depoFRASwapTermStructure); break; } NPV = spot5YearSwap.NPV(); fairRate = spot5YearSwap.fairRate(); fairSpread = spot5YearSwap.fairSpread(); ui->lineEdit_SwapNPV->setText(QString::number(static_cast<double>(NPV),'f')); ui->lineEdit_SwapFairRate->setText(QString::number(static_cast<double>(fairRate*100.0),'f')); ui->lineEdit_SwapFairSpread->setText(QString::number(static_cast<double>(fairSpread*100.0),'f')); }
void CreditDefaultSwapTest::testIsdaEngine() { BOOST_TEST_MESSAGE( "Testing ISDA engine calculations for credit-default swaps..."); SavedSettings backup; Date tradeDate(21, May, 2009); Settings::instance().evaluationDate() = tradeDate; //build an ISDA compliant yield curve //data comes from Markit published rates std::vector<ext::shared_ptr<RateHelper> > isdaRateHelpers; int dep_tenors[] = {1, 2, 3, 6, 9, 12}; double dep_quotes[] = {0.003081, 0.005525, 0.007163, 0.012413, 0.014, 0.015488}; for(size_t i = 0; i < sizeof(dep_tenors) / sizeof(int); i++) { isdaRateHelpers.push_back(ext::make_shared<DepositRateHelper>( dep_quotes[i], dep_tenors[i] * Months, 2, WeekendsOnly(), ModifiedFollowing, false, Actual360() ) ); } int swap_tenors[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 20, 25, 30}; double swap_quotes[] = {0.011907, 0.01699, 0.021198, 0.02444, 0.026937, 0.028967, 0.030504, 0.031719, 0.03279, 0.034535, 0.036217, 0.036981, 0.037246, 0.037605}; ext::shared_ptr<IborIndex> isda_ibor = ext::make_shared<IborIndex>( "IsdaIbor", 3 * Months, 2, USDCurrency(), WeekendsOnly(), ModifiedFollowing, false, Actual360()); for(size_t i = 0; i < sizeof(swap_tenors) / sizeof(int); i++) { isdaRateHelpers.push_back(ext::make_shared<SwapRateHelper>( swap_quotes[i], swap_tenors[i] * Years, WeekendsOnly(), Semiannual, ModifiedFollowing, Thirty360(), isda_ibor ) ); } RelinkableHandle<YieldTermStructure> discountCurve; discountCurve.linkTo( ext::make_shared<PiecewiseYieldCurve<Discount, LogLinear> >( 0, WeekendsOnly(), isdaRateHelpers, Actual365Fixed()) ); RelinkableHandle<DefaultProbabilityTermStructure> probabilityCurve; Date termDates[] = {Date(20, June, 2010), Date(20, June, 2011), Date(20, June, 2012), Date(20, June, 2016), Date(20, June, 2019)}; Rate spreads[] = {0.001, 0.1}; Rate recoveries[] = {0.2, 0.4}; double markitValues[] = {97798.29358, //0.001 97776.11889, //0.001 -914971.5977, //0.1 -894985.6298, //0.1 186921.3594, //0.001 186839.8148, //0.001 -1646623.672, //0.1 -1579803.626, //0.1 274298.9203, 274122.4725, -2279730.93, -2147972.527, 592420.2297, 591571.2294, -3993550.206, -3545843.418, 797501.1422, 795915.9787, -4702034.688, -4042340.999}; #ifndef QL_USE_INDEXED_COUPON Real tolerance = 1.0e-6; #else /* The risk-free curve is a bit off. We might skip the tests altogether and rely on running them with indexed coupons disabled, but leaving them can be useful anyway. */ Real tolerance = 1.0e-3; #endif size_t l = 0; for(size_t i = 0; i < sizeof(termDates) / sizeof(Date); i++) { for(size_t j = 0; j < 2; j++) { for(size_t k = 0; k < 2; k++) { ext::shared_ptr<CreditDefaultSwap> quotedTrade = MakeCreditDefaultSwap(termDates[i], spreads[j]) .withNominal(10000000.); Rate h = quotedTrade->impliedHazardRate(0., discountCurve, Actual365Fixed(), recoveries[k], 1e-10, CreditDefaultSwap::ISDA); probabilityCurve.linkTo( ext::make_shared<FlatHazardRate>( 0, WeekendsOnly(), h, Actual365Fixed()) ); ext::shared_ptr<IsdaCdsEngine> engine = ext::make_shared<IsdaCdsEngine>( probabilityCurve, recoveries[k], discountCurve, boost::none, IsdaCdsEngine::Taylor, IsdaCdsEngine::HalfDayBias, IsdaCdsEngine::Piecewise); ext::shared_ptr<CreditDefaultSwap> conventionalTrade = MakeCreditDefaultSwap(termDates[i], 0.01) .withNominal(10000000.) .withPricingEngine(engine); BOOST_CHECK_CLOSE(conventionalTrade->notional() * conventionalTrade->fairUpfront(), markitValues[l], tolerance); l++; } } } }
void InflationTest::testZeroTermStructure() { BOOST_MESSAGE("Testing zero inflation term structure..."); SavedSettings backup; // try the Zero UK Calendar calendar = UnitedKingdom(); BusinessDayConvention bdc = ModifiedFollowing; Date evaluationDate(13, August, 2007); evaluationDate = calendar.adjust(evaluationDate); Settings::instance().evaluationDate() = evaluationDate; // fixing data Date from(1, January, 2005); Date to(13, August, 2007); Schedule rpiSchedule = MakeSchedule().from(from).to(to) .withTenor(1*Months) .withCalendar(UnitedKingdom()) .withConvention(ModifiedFollowing); Real fixData[] = { 189.9, 189.9, 189.6, 190.5, 191.6, 192.0, 192.2, 192.2, 192.6, 193.1, 193.3, 193.6, 194.1, 193.4, 194.2, 195.0, 196.5, 197.7, 198.5, 198.5, 199.2, 200.1, 200.4, 201.1, 202.7, 201.6, 203.1, 204.4, 205.4, 206.2, 207.3, 206.1, -999.0 }; RelinkableHandle<ZeroInflationTermStructure> hz; bool interp = false; boost::shared_ptr<UKRPI> iiUKRPI(new UKRPI(interp, hz)); for (Size i=0; i<rpiSchedule.size();i++) { iiUKRPI->addFixing(rpiSchedule[i], fixData[i]); } boost::shared_ptr<ZeroInflationIndex> ii = boost::dynamic_pointer_cast<ZeroInflationIndex>(iiUKRPI); boost::shared_ptr<YieldTermStructure> nominalTS = nominalTermStructure(); // now build the zero inflation curve Datum zcData[] = { { Date(13, August, 2008), 2.93 }, { Date(13, August, 2009), 2.95 }, { Date(13, August, 2010), 2.965 }, { Date(15, August, 2011), 2.98 }, { Date(13, August, 2012), 3.0 }, { Date(13, August, 2014), 3.06 }, { Date(13, August, 2017), 3.175 }, { Date(13, August, 2019), 3.243 }, { Date(15, August, 2022), 3.293 }, { Date(14, August, 2027), 3.338 }, { Date(13, August, 2032), 3.348 }, { Date(15, August, 2037), 3.348 }, { Date(13, August, 2047), 3.308 }, { Date(13, August, 2057), 3.228 } }; Period observationLag = Period(2,Months); DayCounter dc = Thirty360(); Frequency frequency = Monthly; std::vector<boost::shared_ptr<BootstrapHelper<ZeroInflationTermStructure> > > helpers = makeHelpers<ZeroInflationTermStructure,ZeroCouponInflationSwapHelper, ZeroInflationIndex>(zcData, LENGTH(zcData), ii, observationLag, calendar, bdc, dc); Rate baseZeroRate = zcData[0].rate/100.0; boost::shared_ptr<PiecewiseZeroInflationCurve<Linear> > pZITS( new PiecewiseZeroInflationCurve<Linear>( evaluationDate, calendar, dc, observationLag, frequency, ii->interpolated(), baseZeroRate, Handle<YieldTermStructure>(nominalTS), helpers)); pZITS->recalculate(); // first check that the zero rates on the curve match the data // and that the helpers give the correct impled rates const Real eps = 0.00000001; bool forceLinearInterpolation = false; for (Size i=0; i<LENGTH(zcData); i++) { BOOST_REQUIRE_MESSAGE(std::fabs(zcData[i].rate/100.0 - pZITS->zeroRate(zcData[i].date, observationLag, forceLinearInterpolation)) < eps, "ZITS zeroRate != instrument " << pZITS->zeroRate(zcData[i].date, observationLag, forceLinearInterpolation) << " vs " << zcData[i].rate/100.0 << " interpolation: " << ii->interpolated() << " forceLinearInterpolation " << forceLinearInterpolation); BOOST_REQUIRE_MESSAGE(std::fabs(helpers[i]->impliedQuote() - zcData[i].rate/100.0) < eps, "ZITS implied quote != instrument " << helpers[i]->impliedQuote() << " vs " << zcData[i].rate/100.0); } // now test the forecasting capability of the index. hz.linkTo(pZITS); from = hz->baseDate(); to = hz->maxDate()-1*Months; // a bit of margin for adjustments Schedule testIndex = MakeSchedule().from(from).to(to) .withTenor(1*Months) .withCalendar(UnitedKingdom()) .withConvention(ModifiedFollowing); // we are testing UKRPI which is not interpolated Date bd = hz->baseDate(); Real bf = ii->fixing(bd); for (Size i=0; i<testIndex.size();i++) { Date d = testIndex[i]; Real z = hz->zeroRate(d, Period(0,Days)); Real t = hz->dayCounter().yearFraction(bd, d); if(!ii->interpolated()) // because fixing constant over period t = hz->dayCounter().yearFraction(bd, inflationPeriod(d, ii->frequency()).first); Real calc = bf * pow( 1+z, t); if (t<=0) calc = ii->fixing(d,false); // still historical if (std::fabs(calc - ii->fixing(d,true))/10000.0 > eps) BOOST_ERROR("ZC index does not forecast correctly for date " << d << " from base date " << bd << " with fixing " << bf << ", correct: " << calc << ", fix: " << ii->fixing(d,true) << ", t " << t); } //=========================================================================================== // Test zero-inflation-indexed (i.e. cpi ratio) cashflow // just ordinary indexed cashflow with a zero inflation index Date baseDate(1, January, 2006); Date fixDate(1, August, 2014); Date payDate=UnitedKingdom().adjust(fixDate+Period(3,Months),ModifiedFollowing); boost::shared_ptr<Index> ind = boost::dynamic_pointer_cast<Index>(ii); BOOST_REQUIRE_MESSAGE(ind,"dynamic_pointer_cast to Index from InflationIndex failed"); Real notional = 1000000.0;//1m IndexedCashFlow iicf(notional,ind,baseDate,fixDate,payDate); Real correctIndexed = ii->fixing(iicf.fixingDate())/ii->fixing(iicf.baseDate()); Real calculatedIndexed = iicf.amount()/iicf.notional(); BOOST_REQUIRE_MESSAGE(std::fabs(correctIndexed - calculatedIndexed) < eps, "IndexedCashFlow indexing wrong: " << calculatedIndexed << " vs correct = " << correctIndexed); //=========================================================================================== // Test zero coupon swap // first make one ... boost::shared_ptr<ZeroInflationIndex> zii = boost::dynamic_pointer_cast<ZeroInflationIndex>(ii); BOOST_REQUIRE_MESSAGE(zii,"dynamic_pointer_cast to ZeroInflationIndex from UKRPI failed"); ZeroCouponInflationSwap nzcis(ZeroCouponInflationSwap::Payer, 1000000.0, evaluationDate, zcData[6].date, // end date = maturity calendar, bdc, dc, zcData[6].rate/100.0, // fixed rate zii, observationLag); // N.B. no coupon pricer because it is not a coupon, effect of inflation curve via // inflation curve attached to the inflation index. Handle<YieldTermStructure> hTS(nominalTS); boost::shared_ptr<PricingEngine> sppe(new DiscountingSwapEngine(hTS)); nzcis.setPricingEngine(sppe); // ... and price it, should be zero BOOST_CHECK_MESSAGE(fabs(nzcis.NPV())<0.00001,"ZCIS does not reprice to zero " << nzcis.NPV() << evaluationDate << " to " << zcData[6].date << " becoming " << nzcis.maturityDate() << " rate " << zcData[6].rate << " fixed leg " << nzcis.legNPV(0) << " indexed-predicted inflated leg " << nzcis.legNPV(1) << " discount " << nominalTS->discount(nzcis.maturityDate()) ); //=========================================================================================== // Test multiplicative seasonality in price // //Seasonality factors NOT normalized //and UKRPI is not interpolated Date trueBaseDate = inflationPeriod(hz->baseDate(), ii->frequency()).second; Date seasonallityBaseDate(31,January,trueBaseDate.year()); std::vector<Rate> seasonalityFactors(12); seasonalityFactors[0] = 1.003245; seasonalityFactors[1] = 1.000000; seasonalityFactors[2] = 0.999715; seasonalityFactors[3] = 1.000495; seasonalityFactors[4] = 1.000929; seasonalityFactors[5] = 0.998687; seasonalityFactors[6] = 0.995949; seasonalityFactors[7] = 0.994682; seasonalityFactors[8] = 0.995949; seasonalityFactors[9] = 1.000519; seasonalityFactors[10] = 1.003705; seasonalityFactors[11] = 1.004186; //Creating two different seasonality objects // boost::shared_ptr<MultiplicativePriceSeasonality> seasonality_1(new MultiplicativePriceSeasonality()); std::vector<Rate> seasonalityFactors_1(12, 1.0); seasonality_1->set(seasonallityBaseDate,Monthly,seasonalityFactors_1); boost::shared_ptr<MultiplicativePriceSeasonality> seasonality_real( new MultiplicativePriceSeasonality(seasonallityBaseDate,Monthly,seasonalityFactors)); //Testing seasonality correction when seasonality factors are = 1 // Rate fixing[] = { ii->fixing(Date(14,January ,2013),true), ii->fixing(Date(14,February ,2013),true), ii->fixing(Date(14,March ,2013),true), ii->fixing(Date(14,April ,2013),true), ii->fixing(Date(14,May ,2013),true), ii->fixing(Date(14,June ,2013),true), ii->fixing(Date(14,July ,2013),true), ii->fixing(Date(14,August ,2013),true), ii->fixing(Date(14,September,2013),true), ii->fixing(Date(14,October ,2013),true), ii->fixing(Date(14,November ,2013),true), ii->fixing(Date(14,December ,2013),true) }; hz->setSeasonality(seasonality_1); QL_REQUIRE(hz->hasSeasonality(),"[44] incorrectly believes NO seasonality correction"); Rate seasonalityFixing_1[] = { ii->fixing(Date(14,January ,2013),true), ii->fixing(Date(14,February ,2013),true), ii->fixing(Date(14,March ,2013),true), ii->fixing(Date(14,April ,2013),true), ii->fixing(Date(14,May ,2013),true), ii->fixing(Date(14,June ,2013),true), ii->fixing(Date(14,July ,2013),true), ii->fixing(Date(14,August ,2013),true), ii->fixing(Date(14,September,2013),true), ii->fixing(Date(14,October ,2013),true), ii->fixing(Date(14,November ,2013),true), ii->fixing(Date(14,December ,2013),true) }; for(int i=0;i<12;i++){ if(std::fabs(fixing[i] - seasonalityFixing_1[i]) > eps) { BOOST_ERROR("Seasonality doesn't work correctly when seasonality factors are set = 1"); } } //Testing seasonality correction when seasonality factors are different from 1 // //0.998687 is the seasonality factor corresponding to June (the base CPI curve month) // Rate expectedFixing[] = { ii->fixing(Date(14,January ,2013),true) * 1.003245/0.998687, ii->fixing(Date(14,February ,2013),true) * 1.000000/0.998687, ii->fixing(Date(14,March ,2013),true) * 0.999715/0.998687, ii->fixing(Date(14,April ,2013),true) * 1.000495/0.998687, ii->fixing(Date(14,May ,2013),true) * 1.000929/0.998687, ii->fixing(Date(14,June ,2013),true) * 0.998687/0.998687, ii->fixing(Date(14,July ,2013),true) * 0.995949/0.998687, ii->fixing(Date(14,August ,2013),true) * 0.994682/0.998687, ii->fixing(Date(14,September,2013),true) * 0.995949/0.998687, ii->fixing(Date(14,October ,2013),true) * 1.000519/0.998687, ii->fixing(Date(14,November ,2013),true) * 1.003705/0.998687, ii->fixing(Date(14,December ,2013),true) * 1.004186/0.998687 }; hz->setSeasonality(seasonality_real); Rate seasonalityFixing_real[] = { ii->fixing(Date(14,January ,2013),true), ii->fixing(Date(14,February ,2013),true), ii->fixing(Date(14,March ,2013),true), ii->fixing(Date(14,April ,2013),true), ii->fixing(Date(14,May ,2013),true), ii->fixing(Date(14,June ,2013),true), ii->fixing(Date(14,July ,2013),true), ii->fixing(Date(14,August ,2013),true), ii->fixing(Date(14,September,2013),true), ii->fixing(Date(14,October ,2013),true), ii->fixing(Date(14,November ,2013),true), ii->fixing(Date(14,December ,2013),true) }; for(int i=0;i<12;i++){ if(std::fabs(expectedFixing[i] - seasonalityFixing_real[i]) > 0.01) { BOOST_ERROR("Seasonality doesn't work correctly when considering seasonality factors != 1 " << expectedFixing[i] << " vs " << seasonalityFixing_real[i]); } } //Testing Unset function // QL_REQUIRE(hz->hasSeasonality(),"[4] incorrectly believes NO seasonality correction"); hz->setSeasonality(); QL_REQUIRE(!hz->hasSeasonality(),"[5] incorrectly believes HAS seasonality correction"); Rate seasonalityFixing_unset[] = { ii->fixing(Date(14,January ,2013),true), ii->fixing(Date(14,February ,2013),true), ii->fixing(Date(14,March ,2013),true), ii->fixing(Date(14,April ,2013),true), ii->fixing(Date(14,May ,2013),true), ii->fixing(Date(14,June ,2013),true), ii->fixing(Date(14,July ,2013),true), ii->fixing(Date(14,August ,2013),true), ii->fixing(Date(14,September,2013),true), ii->fixing(Date(14,October ,2013),true), ii->fixing(Date(14,November ,2013),true), ii->fixing(Date(14,December ,2013),true) }; for(int i=0;i<12;i++){ if(std::fabs(seasonalityFixing_unset[i] - seasonalityFixing_1[i]) > eps) { BOOST_ERROR("UnsetSeasonality doesn't work correctly " << seasonalityFixing_unset[i] << " vs " << seasonalityFixing_1[i]); } } //============================================================================== // now do an INTERPOLATED index, i.e. repeat everything on a fake version of // UKRPI (to save making another term structure) bool interpYES = true; boost::shared_ptr<UKRPI> iiUKRPIyes(new UKRPI(interpYES, hz)); for (Size i=0; i<rpiSchedule.size();i++) { iiUKRPIyes->addFixing(rpiSchedule[i], fixData[i]); } boost::shared_ptr<ZeroInflationIndex> iiyes = boost::dynamic_pointer_cast<ZeroInflationIndex>(iiUKRPIyes); // now build the zero inflation curve // same data, bigger lag or it will be a self-contradiction Period observationLagyes = Period(3,Months); std::vector<boost::shared_ptr<BootstrapHelper<ZeroInflationTermStructure> > > helpersyes = makeHelpers<ZeroInflationTermStructure,ZeroCouponInflationSwapHelper, ZeroInflationIndex>(zcData, LENGTH(zcData), iiyes, observationLagyes, calendar, bdc, dc); boost::shared_ptr<PiecewiseZeroInflationCurve<Linear> > pZITSyes( new PiecewiseZeroInflationCurve<Linear>( evaluationDate, calendar, dc, observationLagyes, frequency, iiyes->interpolated(), baseZeroRate, Handle<YieldTermStructure>(nominalTS), helpersyes)); pZITSyes->recalculate(); // first check that the zero rates on the curve match the data // and that the helpers give the correct impled rates forceLinearInterpolation = false; // still for (Size i=0; i<LENGTH(zcData); i++) { BOOST_CHECK_MESSAGE(std::fabs(zcData[i].rate/100.0 - pZITSyes->zeroRate(zcData[i].date, observationLagyes, forceLinearInterpolation)) < eps, "ZITS INTERPOLATED zeroRate != instrument " << pZITSyes->zeroRate(zcData[i].date, observationLagyes, forceLinearInterpolation) << " date " << zcData[i].date << " observationLagyes " << observationLagyes << " vs " << zcData[i].rate/100.0 << " interpolation: " << iiyes->interpolated() << " forceLinearInterpolation " << forceLinearInterpolation); BOOST_CHECK_MESSAGE(std::fabs(helpersyes[i]->impliedQuote() - zcData[i].rate/100.0) < eps, "ZITS INTERPOLATED implied quote != instrument " << helpersyes[i]->impliedQuote() << " vs " << zcData[i].rate/100.0); } //====================================================================================== // now test the forecasting capability of the index. hz.linkTo(pZITSyes); from = hz->baseDate()+1*Months; // to avoid historical linear bit for rest of base month to = hz->maxDate()-1*Months; // a bit of margin for adjustments testIndex = MakeSchedule().from(from).to(to) .withTenor(1*Months) .withCalendar(UnitedKingdom()) .withConvention(ModifiedFollowing); // we are testing UKRPI which is FAKE interpolated for testing here bd = hz->baseDate(); bf = iiyes->fixing(bd); for (Size i=0; i<testIndex.size();i++) { Date d = testIndex[i]; Real z = hz->zeroRate(d, Period(0,Days)); Real t = hz->dayCounter().yearFraction(bd, d); Real calc = bf * pow( 1+z, t); if (t<=0) calc = iiyes->fixing(d); // still historical if (std::fabs(calc - iiyes->fixing(d)) > eps) BOOST_ERROR("ZC INTERPOLATED index does not forecast correctly for date " << d << " from base date " << bd << " with fixing " << bf << ", correct: " << calc << ", fix: " << iiyes->fixing(d) << ", t " << t << ", zero " << z); } //=========================================================================================== // Test zero coupon swap boost::shared_ptr<ZeroInflationIndex> ziiyes = boost::dynamic_pointer_cast<ZeroInflationIndex>(iiyes); BOOST_REQUIRE_MESSAGE(ziiyes,"dynamic_pointer_cast to ZeroInflationIndex from UKRPI-I failed"); ZeroCouponInflationSwap nzcisyes(ZeroCouponInflationSwap::Payer, 1000000.0, evaluationDate, zcData[6].date, // end date = maturity calendar, bdc, dc, zcData[6].rate/100.0, // fixed rate ziiyes, observationLagyes); // N.B. no coupon pricer because it is not a coupon, effect of inflation curve via // inflation curve attached to the inflation index. nzcisyes.setPricingEngine(sppe); // ... and price it, should be zero BOOST_CHECK_MESSAGE(fabs(nzcisyes.NPV())<0.00001,"ZCIS-I does not reprice to zero " << nzcisyes.NPV() << evaluationDate << " to " << zcData[6].date << " becoming " << nzcisyes.maturityDate() << " rate " << zcData[6].rate << " fixed leg " << nzcisyes.legNPV(0) << " indexed-predicted inflated leg " << nzcisyes.legNPV(1) << " discount " << nominalTS->discount(nzcisyes.maturityDate()) ); }
int main(int, char* []) { try { boost::timer timer; std::cout << std::endl; Date repoSettlementDate(14,February,2000);; Date repoDeliveryDate(15,August,2000); Rate repoRate = 0.05; DayCounter repoDayCountConvention = Actual360(); Integer repoSettlementDays = 0; Compounding repoCompounding = Simple; Frequency repoCompoundFreq = Annual; // assume a ten year bond- this is irrelevant Date bondIssueDate(15,September,1995); Date bondDatedDate(15,September,1995); Date bondMaturityDate(15,September,2005); Real bondCoupon = 0.08; Frequency bondCouponFrequency = Semiannual; // unknown what calendar fincad is using Calendar bondCalendar = NullCalendar(); DayCounter bondDayCountConvention = Thirty360(Thirty360::BondBasis); // unknown what fincad is using. this may affect accrued calculation Integer bondSettlementDays = 0; BusinessDayConvention bondBusinessDayConvention = Unadjusted; Real bondCleanPrice = 89.97693786; Real bondRedemption = 100.0; Real faceAmount = 100.0; Settings::instance().evaluationDate() = repoSettlementDate; RelinkableHandle<YieldTermStructure> bondCurve; bondCurve.linkTo(boost::shared_ptr<YieldTermStructure>( new FlatForward(repoSettlementDate, .01, // dummy rate bondDayCountConvention, Compounded, bondCouponFrequency))); /* boost::shared_ptr<FixedRateBond> bond( new FixedRateBond(faceAmount, bondIssueDate, bondDatedDate, bondMaturityDate, bondSettlementDays, std::vector<Rate>(1,bondCoupon), bondCouponFrequency, bondCalendar, bondDayCountConvention, bondBusinessDayConvention, bondBusinessDayConvention, bondRedemption, bondCurve)); */ Schedule bondSchedule(bondDatedDate, bondMaturityDate, Period(bondCouponFrequency), bondCalendar,bondBusinessDayConvention, bondBusinessDayConvention, DateGeneration::Backward,false); boost::shared_ptr<FixedRateBond> bond( new FixedRateBond(bondSettlementDays, faceAmount, bondSchedule, std::vector<Rate>(1,bondCoupon), bondDayCountConvention, bondBusinessDayConvention, bondRedemption, bondIssueDate)); bond->setPricingEngine(boost::shared_ptr<PricingEngine>( new DiscountingBondEngine(bondCurve))); bondCurve.linkTo(boost::shared_ptr<YieldTermStructure> ( new FlatForward(repoSettlementDate, bond->yield(bondCleanPrice, bondDayCountConvention, Compounded, bondCouponFrequency), bondDayCountConvention, Compounded, bondCouponFrequency))); Position::Type fwdType = Position::Long; double dummyStrike = 91.5745; RelinkableHandle<YieldTermStructure> repoCurve; repoCurve.linkTo(boost::shared_ptr<YieldTermStructure> ( new FlatForward(repoSettlementDate, repoRate, repoDayCountConvention, repoCompounding, repoCompoundFreq))); FixedRateBondForward bondFwd(repoSettlementDate, repoDeliveryDate, fwdType, dummyStrike, repoSettlementDays, repoDayCountConvention, bondCalendar, bondBusinessDayConvention, bond, repoCurve, repoCurve); cout << "Underlying bond clean price: " << bond->cleanPrice() << endl; cout << "Underlying bond dirty price: " << bond->dirtyPrice() << endl; cout << "Underlying bond accrued at settlement: " << bond->accruedAmount(repoSettlementDate) << endl; cout << "Underlying bond accrued at delivery: " << bond->accruedAmount(repoDeliveryDate) << endl; cout << "Underlying bond spot income: " << bondFwd.spotIncome(repoCurve) << endl; cout << "Underlying bond fwd income: " << bondFwd.spotIncome(repoCurve)/ repoCurve->discount(repoDeliveryDate) << endl; cout << "Repo strike: " << dummyStrike << endl; cout << "Repo NPV: " << bondFwd.NPV() << endl; cout << "Repo clean forward price: " << bondFwd.cleanForwardPrice() << endl; cout << "Repo dirty forward price: " << bondFwd.forwardPrice() << endl; cout << "Repo implied yield: " << bondFwd.impliedYield(bond->dirtyPrice(), dummyStrike, repoSettlementDate, repoCompounding, repoDayCountConvention) << endl; cout << "Market repo rate: " << repoCurve->zeroRate(repoDeliveryDate, repoDayCountConvention, repoCompounding, repoCompoundFreq) << endl << endl; cout << "Compare with example given at \n" << "http://www.fincad.com/support/developerFunc/mathref/BFWD.htm" << endl; cout << "Clean forward price = 88.2408" << endl << endl; cout << "In that example, it is unknown what bond calendar they are\n" << "using, as well as settlement Days. For that reason, I have\n" << "made the simplest possible assumptions here: NullCalendar\n" << "and 0 settlement days." << endl; double seconds = timer.elapsed(); Integer hours = int(seconds/3600); seconds -= hours * 3600; Integer minutes = int(seconds/60); seconds -= minutes * 60; cout << " \nRun completed in "; if (hours > 0) cout << hours << " h "; if (hours > 0 || minutes > 0) cout << minutes << " m "; cout << fixed << setprecision(0) << seconds << " s\n" << endl; return 0; } catch (exception& e) { cerr << e.what() << endl; return 1; } catch (...) { cerr << "unknown error" << endl; return 1; } }
void MCLongstaffSchwartzEngineTest::testAmericanMaxOption() { // reference values taken from // "Monte Carlo Methods in Financial Engineering", // by Paul Glasserman, 2004 Springer Verlag, p. 462 BOOST_TEST_MESSAGE("Testing Monte-Carlo pricing of American max options..."); SavedSettings backup; // most of the example taken from the EquityOption.cpp const Option::Type type(Option::Call); const Real strike = 100; const Spread dividendYield = 0.10; const Rate riskFreeRate = 0.05; const Volatility volatility = 0.20; const Date todaysDate(15, May, 1998); const Date settlementDate(17, May, 1998); Settings::instance().evaluationDate() = todaysDate; const Date maturity(16, May, 2001); const DayCounter dayCounter = Actual365Fixed(); boost::shared_ptr<Exercise> americanExercise( new AmericanExercise(settlementDate, maturity)); // bootstrap the yield/dividend/vol curves Handle<YieldTermStructure> flatTermStructure( boost::shared_ptr<YieldTermStructure>( new FlatForward(settlementDate, riskFreeRate, dayCounter))); Handle<YieldTermStructure> flatDividendTS( boost::shared_ptr<YieldTermStructure>( new FlatForward(settlementDate, dividendYield, dayCounter))); Handle<BlackVolTermStructure> flatVolTS( boost::shared_ptr<BlackVolTermStructure>(new BlackConstantVol(settlementDate, NullCalendar(), volatility, dayCounter))); boost::shared_ptr<StrikedTypePayoff> payoff( new PlainVanillaPayoff(type, strike)); RelinkableHandle<Quote> underlyingH; boost::shared_ptr<GeneralizedBlackScholesProcess> stochasticProcess(new GeneralizedBlackScholesProcess( underlyingH, flatDividendTS, flatTermStructure, flatVolTS)); const Size numberAssets = 2; Matrix corr(numberAssets, numberAssets, 0.0); std::vector<boost::shared_ptr<StochasticProcess1D> > v; for (Size i=0; i<numberAssets; ++i) { v.push_back(stochasticProcess); corr[i][i] = 1.0; } boost::shared_ptr<StochasticProcessArray> process( new StochasticProcessArray(v, corr)); VanillaOption americanMaxOption(payoff, americanExercise); boost::shared_ptr<PricingEngine> mcengine( new MCAmericanMaxEngine<PseudoRandom>(process, 25, Null<Size>(), false, true, false, 4096, Null<Real>(), Null<Size>(), 42, 1024)); americanMaxOption.setPricingEngine(mcengine); const Real expected[] = {8.08, 13.90, 21.34}; for (Size i = 0; i < 3; ++i) { const Real underlying = 90.0 + i*10.0; underlyingH.linkTo( boost::shared_ptr<Quote>(new SimpleQuote(underlying))); const Real calculated = americanMaxOption.NPV(); const Real errorEstimate = americanMaxOption.errorEstimate(); if (std::fabs(calculated - expected[i]) > 2.34*errorEstimate) { BOOST_ERROR("Failed to reproduce american option prices" << "\n expected: " << expected[i] << "\n calculated: " << calculated << " +/- " << errorEstimate); } } }
void CdsOptionTest::testCached() { BOOST_TEST_MESSAGE("Testing CDS-option value against cached values..."); SavedSettings backup; Date cachedToday = Date(10,December,2007); Settings::instance().evaluationDate() = cachedToday; Calendar calendar = TARGET(); RelinkableHandle<YieldTermStructure> riskFree; riskFree.linkTo(boost::shared_ptr<YieldTermStructure>( new FlatForward(cachedToday,0.02,Actual360()))); Date expiry = calendar.advance(cachedToday,9,Months); Date startDate = calendar.advance(expiry,1,Months); Date maturity = calendar.advance(startDate,7,Years); DayCounter dayCounter = Actual360(); BusinessDayConvention convention = ModifiedFollowing; Real notional = 1000000.0; Handle<Quote> hazardRate(boost::shared_ptr<Quote>(new SimpleQuote(0.001))); Schedule schedule(startDate,maturity, Period(Quarterly), calendar, convention, convention, DateGeneration::Forward, false); Real recoveryRate = 0.4; Handle<DefaultProbabilityTermStructure> defaultProbability( boost::shared_ptr<DefaultProbabilityTermStructure>( new FlatHazardRate(0, calendar, hazardRate, dayCounter))); boost::shared_ptr<PricingEngine> swapEngine( new MidPointCdsEngine(defaultProbability, recoveryRate, riskFree)); CreditDefaultSwap swap(Protection::Seller, notional, 0.001, schedule, convention, dayCounter); swap.setPricingEngine(swapEngine); Rate strike = swap.fairSpread(); Handle<Quote> cdsVol(boost::shared_ptr<Quote>(new SimpleQuote(0.20))); boost::shared_ptr<CreditDefaultSwap> underlying( new CreditDefaultSwap(Protection::Seller, notional, strike, schedule, convention, dayCounter)); underlying->setPricingEngine(swapEngine); boost::shared_ptr<Exercise> exercise(new EuropeanExercise(expiry)); CdsOption option1(underlying, exercise); option1.setPricingEngine(boost::shared_ptr<PricingEngine>( new BlackCdsOptionEngine(defaultProbability, recoveryRate, riskFree, cdsVol))); Real cachedValue = 270.976348; if (std::fabs(option1.NPV() - cachedValue) > 1.0e-5) BOOST_ERROR("failed to reproduce cached value:\n" << std::fixed << std::setprecision(6) << " calculated: " << option1.NPV() << "\n" << " expected: " << cachedValue); underlying = boost::shared_ptr<CreditDefaultSwap>( new CreditDefaultSwap(Protection::Buyer, notional, strike, schedule, convention, dayCounter)); underlying->setPricingEngine(swapEngine); CdsOption option2(underlying, exercise); option2.setPricingEngine(boost::shared_ptr<PricingEngine>( new BlackCdsOptionEngine(defaultProbability, recoveryRate, riskFree, cdsVol))); cachedValue = 270.976348; if (std::fabs(option2.NPV() - cachedValue) > 1.0e-5) BOOST_ERROR("failed to reproduce cached value:\n" << std::fixed << std::setprecision(6) << " calculated: " << option2.NPV() << "\n" << " expected: " << cachedValue); }