C++

CVA_IRS

/*
 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;
    }
}