/* Basket Losses */ /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ #include <ql/quantlib.hpp> #include <boost/timer.hpp> #include <boost/make_shared.hpp> #include <boost/function.hpp> #include <boost/assign/std/vector.hpp> #include <iostream> #include <iomanip> using namespace std; using namespace QuantLib; using namespace boost::assign; #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 int main(int, char* []) { try { boost::timer timer; std::cout << std::endl; Calendar calendar = TARGET(); Date todaysDate(19, March, 2014); // must be a business day todaysDate = calendar.adjust(todaysDate); Settings::instance().evaluationDate() = todaysDate; /* -------------------------------------------------------------- SET UP BASKET PORTFOLIO -------------------------------------------------------------- */ // build curves and issuers into a basket of ten names std::vector<Real> hazardRates; hazardRates += // 0.01, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9; 0.001, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09; // 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01; std::vector<std::string> names; for(Size i=0; i<hazardRates.size(); i++) names.push_back(std::string("Acme") + boost::lexical_cast<std::string>(i)); std::vector<Handle<DefaultProbabilityTermStructure> > defTS; for(Size i=0; i<hazardRates.size(); i++) { defTS.push_back(Handle<DefaultProbabilityTermStructure>( boost::make_shared<FlatHazardRate>(0, TARGET(), hazardRates[i], Actual365Fixed()))); defTS.back()->enableExtrapolation(); } std::vector<Issuer> issuers; for(Size i=0; i<hazardRates.size(); i++) { std::vector<QuantLib::Issuer::key_curve_pair> curves(1, std::make_pair(NorthAmericaCorpDefaultKey( EURCurrency(), QuantLib::SeniorSec, Period(), 1. // amount threshold ), defTS[i])); issuers.push_back(Issuer(curves)); } boost::shared_ptr<Pool> thePool = boost::make_shared<Pool>(); for(Size i=0; i<hazardRates.size(); i++) thePool->add(names[i], issuers[i], NorthAmericaCorpDefaultKey( EURCurrency(), QuantLib::SeniorSec, Period(), 1.)); std::vector<DefaultProbKey> defaultKeys(hazardRates.size(), NorthAmericaCorpDefaultKey(EURCurrency(), SeniorSec, Period(), 1.)); boost::shared_ptr<Basket> theBskt = boost::make_shared<Basket>( todaysDate, names, std::vector<Real>(hazardRates.size(), 100.), thePool, // 0.0, 0.78); 0.03, .06); /* -------------------------------------------------------------- SET UP DEFAULT LOSS MODELS -------------------------------------------------------------- */ std::vector<Real> recoveries(hazardRates.size(), 0.4); Date calcDate(TARGET().advance(Settings::instance().evaluationDate(), Period(60, Months))); Real factorValue = 0.05; std::vector<std::vector<Real> > fctrsWeights(hazardRates.size(), std::vector<Real>(1, std::sqrt(factorValue))); // --- LHP model -------------------------- boost::shared_ptr<DefaultLossModel> lmGLHP( boost::make_shared<GaussianLHPLossModel>( fctrsWeights[0][0] * fctrsWeights[0][0], recoveries)); theBskt->setLossModel(lmGLHP); std::cout << "GLHP Expected 10-Yr Losses: " << std::endl; std::cout << theBskt->expectedTrancheLoss(calcDate) << std::endl; // --- G Binomial model -------------------- boost::shared_ptr<GaussianConstantLossLM> ktLossLM( boost::make_shared<GaussianConstantLossLM>(fctrsWeights, recoveries, LatentModelIntegrationType::GaussianQuadrature, GaussianCopulaPolicy::initTraits())); boost::shared_ptr<DefaultLossModel> lmBinomial( boost::make_shared<GaussianBinomialLossModel>(ktLossLM)); theBskt->setLossModel(lmBinomial); std::cout << "Gaussian Binomial Expected 10-Yr Losses: " << std::endl; std::cout << theBskt->expectedTrancheLoss(calcDate) << std::endl; // --- T Binomial model -------------------- TCopulaPolicy::initTraits initT; initT.tOrders = std::vector<Integer>(2, 3); boost::shared_ptr<TConstantLossLM> ktTLossLM( boost::make_shared<TConstantLossLM>(fctrsWeights, recoveries, //LatentModelIntegrationType::GaussianQuadrature, LatentModelIntegrationType::Trapezoid, initT)); boost::shared_ptr<DefaultLossModel> lmTBinomial( boost::make_shared<TBinomialLossModel>(ktTLossLM)); theBskt->setLossModel(lmTBinomial); std::cout << "T Binomial Expected 10-Yr Losses: " << std::endl; std::cout << theBskt->expectedTrancheLoss(calcDate) << std::endl; // --- G Inhomogeneous model --------------- boost::shared_ptr<GaussianConstantLossLM> gLM( boost::make_shared<GaussianConstantLossLM>(fctrsWeights, recoveries, LatentModelIntegrationType::GaussianQuadrature, // g++ requires this when using make_shared GaussianCopulaPolicy::initTraits())); Size numBuckets = 100; boost::shared_ptr<DefaultLossModel> inhomogeneousLM( boost::make_shared<IHGaussPoolLossModel>(gLM, numBuckets)); theBskt->setLossModel(inhomogeneousLM); std::cout << "G Inhomogeneous Expected 10-Yr Losses: " << std::endl; std::cout << theBskt->expectedTrancheLoss(calcDate) << std::endl; // --- G Random model --------------------- // Gaussian random joint default model: Size numSimulations = 100000; // Size numCoresUsed = 4; // Sobol, many cores boost::shared_ptr<DefaultLossModel> rdlmG( boost::make_shared<RandomDefaultLM<GaussianCopulaPolicy, RandomSequenceGenerator< BoxMullerGaussianRng<MersenneTwisterUniformRng> > > >(gLM, recoveries, numSimulations, 1.e-6, 2863311530)); //boost::shared_ptr<DefaultLossModel> rdlmG( // boost::make_shared<RandomDefaultLM<GaussianCopulaPolicy> >(gLM, // recoveries, numSimulations, 1.e-6, 2863311530)); theBskt->setLossModel(rdlmG); std::cout << "Random G Expected 10-Yr Losses: " << std::endl; std::cout << theBskt->expectedTrancheLoss(calcDate) << std::endl; // --- StudentT Random model --------------------- // Sobol, many cores boost::shared_ptr<DefaultLossModel> rdlmT( boost::make_shared<RandomDefaultLM<TCopulaPolicy, RandomSequenceGenerator< PolarStudentTRng<MersenneTwisterUniformRng> > > >(ktTLossLM, recoveries, numSimulations, 1.e-6, 2863311530)); //boost::shared_ptr<DefaultLossModel> rdlmT( // boost::make_shared<RandomDefaultLM<TCopulaPolicy> >(ktTLossLM, // recoveries, numSimulations, 1.e-6, 2863311530)); theBskt->setLossModel(rdlmT); std::cout << "Random T Expected 10-Yr Losses: " << std::endl; std::cout << theBskt->expectedTrancheLoss(calcDate) << std::endl; // Spot Loss latent model: std::vector<std::vector<Real> > fctrsWeightsRR(2 * hazardRates.size(), std::vector<Real>(1, std::sqrt(factorValue))); Real modelA = 2.2; boost::shared_ptr<GaussianSpotLossLM> sptLG(new GaussianSpotLossLM( fctrsWeightsRR, recoveries, modelA, LatentModelIntegrationType::GaussianQuadrature, GaussianCopulaPolicy::initTraits())); boost::shared_ptr<TSpotLossLM> sptLT(new TSpotLossLM(fctrsWeightsRR, recoveries, modelA, LatentModelIntegrationType::GaussianQuadrature, initT)); // --- G Random Loss model --------------------- // Gaussian random joint default model: // Sobol, many cores boost::shared_ptr<DefaultLossModel> rdLlmG( boost::make_shared<RandomLossLM<GaussianCopulaPolicy> >(sptLG, numSimulations, 1.e-6, 2863311530)); theBskt->setLossModel(rdLlmG); std::cout << "Random Loss G Expected 10-Yr Losses: " << std::endl; std::cout << theBskt->expectedTrancheLoss(calcDate) << std::endl; // --- T Random Loss model --------------------- // Gaussian random joint default model: // Sobol, many cores boost::shared_ptr<DefaultLossModel> rdLlmT( boost::make_shared<RandomLossLM<TCopulaPolicy> >(sptLT, numSimulations, 1.e-6, 2863311530)); theBskt->setLossModel(rdLlmT); std::cout << "Random Loss T Expected 10-Yr Losses: " << std::endl; std::cout << theBskt->expectedTrancheLoss(calcDate) << std::endl; // Base Correlation model set up to test cocherence with base LHP model std::vector<Period> bcTenors; bcTenors.push_back(Period(1, Years)); bcTenors.push_back(Period(5, Years)); std::vector<Real> bcLossPercentages; bcLossPercentages.push_back(0.03); bcLossPercentages.push_back(0.12); std::vector<std::vector<Handle<Quote> > > correls; // std::vector<Handle<Quote> > corr1Y; // 3% corr1Y.push_back(Handle<Quote>(boost::shared_ptr<Quote>( new SimpleQuote(fctrsWeights[0][0] * fctrsWeights[0][0])))); // 12% corr1Y.push_back(Handle<Quote>(boost::shared_ptr<Quote>( new SimpleQuote(fctrsWeights[0][0] * fctrsWeights[0][0])))); correls.push_back(corr1Y); std::vector<Handle<Quote> > corr2Y; // 3% corr2Y.push_back(Handle<Quote>(boost::shared_ptr<Quote>( new SimpleQuote(fctrsWeights[0][0] * fctrsWeights[0][0])))); // 12% corr2Y.push_back(Handle<Quote>(boost::shared_ptr<Quote>( new SimpleQuote(fctrsWeights[0][0] * fctrsWeights[0][0])))); correls.push_back(corr2Y); boost::shared_ptr<BaseCorrelationTermStructure<BilinearInterpolation> > correlSurface( new BaseCorrelationTermStructure<BilinearInterpolation>( // first one would do, all should be the same. defTS[0]->settlementDays(), defTS[0]->calendar(), Unadjusted, bcTenors, bcLossPercentages, correls, Actual365Fixed() ) ); Handle<BaseCorrelationTermStructure<BilinearInterpolation> > correlHandle(correlSurface); boost::shared_ptr<DefaultLossModel> bcLMG_LHP_Bilin( boost::make_shared<GaussianLHPFlatBCLM>(correlHandle, recoveries, GaussianCopulaPolicy::initTraits())); theBskt->setLossModel(bcLMG_LHP_Bilin); std::cout << "Base Correlation GLHP Expected 10-Yr Losses: " << std::endl; std::cout << theBskt->expectedTrancheLoss(calcDate) << std::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; } }