/* CVA IRS */ /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ #include <ql/quantlib.hpp> #include <boost/timer.hpp> #include <iostream> #include <iomanip> using namespace std; using namespace QuantLib; #ifdef BOOST_MSVC # ifdef QL_ENABLE_THREAD_SAFE_OBSERVER_PATTERN # include <ql/auto_link.hpp> # define BOOST_LIB_NAME boost_system # include <boost/config/auto_link.hpp> # undef BOOST_LIB_NAME # define BOOST_LIB_NAME boost_thread # include <boost/config/auto_link.hpp> # undef BOOST_LIB_NAME # endif #endif #if defined(QL_ENABLE_SESSIONS) namespace QuantLib { Integer sessionId() { return 0; } } #endif /* This example reproduces Table 2 on page 11 of A Formula for Interest Rate Swaps Valuation under Counterparty Risk in presence of Netting Agreements Damiano Brigo and Massimo Masetti; May 4, 2005 */ int main(int, char* []) { try { boost::timer timer; std::cout << std::endl; Calendar calendar = TARGET(); Date todaysDate(10, March, 2004); // must be a business day todaysDate = calendar.adjust(todaysDate); Settings::instance().evaluationDate() = todaysDate; boost::shared_ptr<IborIndex> yieldIndx(new Euribor3M()); Size tenorsSwapMkt[] = {5, 10, 15, 20, 25, 30}; // rates ignoring counterparty risk: Rate ratesSwapmkt[] = {.03249, .04074, .04463, .04675, .04775, .04811}; vector<boost::shared_ptr<RateHelper> > swapHelpers; for(Size i=0; i<sizeof(tenorsSwapMkt)/sizeof(Size); i++) swapHelpers.push_back(boost::make_shared<SwapRateHelper>( Handle<Quote>(boost::shared_ptr<Quote>( new SimpleQuote(ratesSwapmkt[i]))), tenorsSwapMkt[i] * Years, TARGET(), Quarterly, ModifiedFollowing, ActualActual(ActualActual::ISDA), yieldIndx)); boost::shared_ptr<YieldTermStructure> swapTS( new PiecewiseYieldCurve<Discount,LogLinear>( 2, TARGET(), swapHelpers, ActualActual(ActualActual::ISDA), 1.0e-12)); swapTS->enableExtrapolation(); boost::shared_ptr<PricingEngine> riskFreeEngine( boost::make_shared<DiscountingSwapEngine>( Handle<YieldTermStructure>(swapTS))); std::vector<Handle<DefaultProbabilityTermStructure> > defaultIntensityTS; Size defaultTenors[] = {0, 12, 36, 60, 84, 120, 180, 240, 300, 360};// months // Three risk levels: Real intensitiesLow[] = {0.0036, 0.0036, 0.0065, 0.0099, 0.0111, 0.0177, 0.0177, 0.0177, 0.0177, 0.0177, 0.0177}; Real intensitiesMedium[] = {0.0202, 0.0202, 0.0231, 0.0266, 0.0278, 0.0349, 0.0349, 0.0349, 0.0349, 0.0349, 0.0349}; Real intensitiesHigh[] = {0.0534, 0.0534, 0.0564, 0.06, 0.0614, 0.0696, 0.0696, 0.0696, 0.0696, 0.0696, 0.0696}; // Recovery rates: Real ctptyRRLow = 0.4, ctptyRRMedium = 0.35, ctptyRRHigh = 0.3; std::vector<Date> defaultTSDates; std::vector<Real> intesitiesVLow, intesitiesVMedium, intesitiesVHigh; for(Size i=0; i<sizeof(defaultTenors)/sizeof(Size); i++) { defaultTSDates.push_back(TARGET().advance(todaysDate, Period(defaultTenors[i], Months))); intesitiesVLow.push_back(intensitiesLow[i]); intesitiesVMedium.push_back(intensitiesMedium[i]); intesitiesVHigh.push_back(intensitiesHigh[i]); } defaultIntensityTS.push_back(Handle<DefaultProbabilityTermStructure>( boost::shared_ptr<DefaultProbabilityTermStructure>( new InterpolatedHazardRateCurve<BackwardFlat>( defaultTSDates, intesitiesVLow, Actual360(), TARGET())))); defaultIntensityTS.push_back(Handle<DefaultProbabilityTermStructure>( boost::shared_ptr<DefaultProbabilityTermStructure>( new InterpolatedHazardRateCurve<BackwardFlat>( defaultTSDates, intesitiesVMedium, Actual360(), TARGET())))); defaultIntensityTS.push_back(Handle<DefaultProbabilityTermStructure>( boost::shared_ptr<DefaultProbabilityTermStructure>( new InterpolatedHazardRateCurve<BackwardFlat>( defaultTSDates, intesitiesVHigh, Actual360(), TARGET())))); Volatility blackVol = 0.15; boost::shared_ptr<PricingEngine> ctptySwapCvaLow = boost::make_shared<CounterpartyAdjSwapEngine>( Handle<YieldTermStructure>(swapTS), blackVol, defaultIntensityTS[0], ctptyRRLow ); boost::shared_ptr<PricingEngine> ctptySwapCvaMedium = boost::make_shared<CounterpartyAdjSwapEngine>( Handle<YieldTermStructure>(swapTS), blackVol, defaultIntensityTS[1], ctptyRRMedium); boost::shared_ptr<PricingEngine> ctptySwapCvaHigh = boost::make_shared<CounterpartyAdjSwapEngine>( Handle<YieldTermStructure>(swapTS), blackVol, defaultIntensityTS[2], ctptyRRHigh); defaultIntensityTS[0]->enableExtrapolation(); defaultIntensityTS[1]->enableExtrapolation(); defaultIntensityTS[2]->enableExtrapolation(); /// SWAP RISKY REPRICE---------------------------------------------- // fixed leg Frequency fixedLegFrequency = Quarterly; BusinessDayConvention fixedLegConvention = ModifiedFollowing; DayCounter fixedLegDayCounter = ActualActual(ActualActual::ISDA); DayCounter floatingLegDayCounter = ActualActual(ActualActual::ISDA); VanillaSwap::Type swapType = //VanillaSwap::Receiver ; VanillaSwap::Payer; boost::shared_ptr<IborIndex> yieldIndxS( new Euribor3M(Handle<YieldTermStructure>(swapTS))); std::vector<VanillaSwap> riskySwaps; for(Size i=0; i<sizeof(tenorsSwapMkt)/sizeof(Size); i++) riskySwaps.push_back(MakeVanillaSwap(tenorsSwapMkt[i]*Years, yieldIndxS, ratesSwapmkt[i], 0*Days) .withSettlementDays(2) .withFixedLegDayCount(fixedLegDayCounter) .withFixedLegTenor(Period(fixedLegFrequency)) .withFixedLegConvention(fixedLegConvention) .withFixedLegTerminationDateConvention(fixedLegConvention) .withFixedLegCalendar(calendar) .withFloatingLegCalendar(calendar) .withNominal(100.) .withType(swapType)); cout << "-- Correction in the contract fix rate in bp --" << endl; /* The paper plots correction to be substracted, here is printed with its sign */ for(Size i=0; i<riskySwaps.size(); i++) { cout << fixed << setprecision(3); cout << setw(4); riskySwaps[i].setPricingEngine(riskFreeEngine); // should recover the input here: Real nonRiskyFair = riskySwaps[i].fairRate(); cout << tenorsSwapMkt[i]; cout << setw(5); cout << " | " << io::rate(nonRiskyFair); cout << fixed << setprecision(2); cout << setw(5); // Low Risk: riskySwaps[i].setPricingEngine(ctptySwapCvaLow); cout << " | " << setw(6) << 10000.*(riskySwaps[i].fairRate() - nonRiskyFair); //cout << " | " << setw(6) << riskySwaps[i].NPV() ; // Medium Risk: riskySwaps[i].setPricingEngine(ctptySwapCvaMedium); cout << " | " << setw(6) << 10000.*(riskySwaps[i].fairRate() - nonRiskyFair); //cout << " | " << setw(6) << riskySwaps[i].NPV() ; riskySwaps[i].setPricingEngine(ctptySwapCvaHigh); cout << " | " << setw(6) << 10000.*(riskySwaps[i].fairRate() - nonRiskyFair); //cout << " | " << setw(6) << riskySwaps[i].NPV() ; cout << endl; } cout << endl; Real seconds = timer.elapsed(); Integer hours = Integer(seconds/3600); seconds -= hours * 3600; Integer minutes = Integer(seconds/60); seconds -= minutes * 60; cout << "Run completed in "; if (hours > 0) cout << hours << " h "; if (hours > 0 || minutes > 0) cout << minutes << " m "; cout << fixed << setprecision(0) << seconds << " s" << endl; return 0; } catch (exception& e) { cerr << e.what() << endl; return 1; } catch (...) { cerr << "unknown error" << endl; return 1; } }