Loading...
Home / NPV Difference of CNY Swap between QuantExt and BBG

Home Forums Help NPV Difference of CNY Swap between QuantExt and BBG

Tagged: 

This topic contains 1 reply, has 1 voice, and was last updated by  steve 3 months, 2 weeks ago.

Viewing 2 posts - 1 through 2 (of 2 total)
  • Author
    Posts
  • #6638

    steve
    Participant

    Dear all,
    I am trying to value a CNY Swap.
    The floating leg of CNY Swap is a 7 day repo rate.
    The payment freq of floating leg and fixed leg is quarterly.
    The interest rate of floating leg is compounded by 7 day repo rates.

    I use the SubPeriodsSwap/SubPeriodSwapHelper/SubperiodsCoupon in QuantExt.
    I make an instance of 3 year swap. I compare the NPV with Bloomberg on some backdated trades.
    Currently, there is no CNY 7d Repo index in QuantLib, so I make a cnyrepo.cpp

    My result comparison with Bloomberg and code are as below. Thanks.
    Curve1 : the market curve on 2019/2/14.
    Curve2 : I raise the 3 year swap rate to 3.0%.

    ==Curve Terms==
    Today Valuation Date
    2019/2/14 2019/2/15

    ==Swap Terms==
    Settlement Date 2018/9/3
    Tenor 3 years
    Fixed Rate 2.611%

    Curve_1 My Result Bloomberg Result
    NPV 727.19 1,001.61
    FairRate 2.5837% 2.5734%

    Curve_2 My Result Bloomberg Result
    NPV 5,494.60 4,388.60
    FairRate 2.8200% 2.7758%

    I think the difference is not OK. I am not sure if I did any thing wrong.
    The code to vlaue CNY Swap and the cnyrepo.cpp are as below.

    //Code to Value CNY Swap
    //=============================================================================================//

    using namespace QuantLib;
    using namespace QuantExt;
    using namespace std;
    
    int main() {
        try {
    
            /*********************
             ***  MARKET DATA  ***
             *********************/
    
            Calendar calendar = China(China::IB);
            calendar.removeHoliday(Date(30, December, 2018));
            calendar.removeHoliday(Date(2, February, 2019));
            calendar.removeHoliday(Date(3, February, 2019));
            calendar.addHoliday(Date(4, February, 2019));
            calendar.addHoliday(Date(5, February, 2019));
            calendar.addHoliday(Date(6, February, 2019));
            calendar.addHoliday(Date(7, February, 2019));
            calendar.addHoliday(Date(8, February, 2019));
    
            Date valuationDate(15, February, 2019);
            valuationDate = calendar.adjust(valuationDate);
            Integer fixingDays = 1;
            Date todaysDate = calendar.advance(valuationDate, -fixingDays, Days);
            Settings::instance().evaluationDate() = todaysDate;
    
            todaysDate = Settings::instance().evaluationDate();
            std::cout << "Today: " << todaysDate.weekday() << ", " << todaysDate << std::endl;
    
            std::cout << "Settlement date: " << valuationDate.weekday() << ", " << valuationDate << std::endl;
    
            // deposits
            Rate d1DQuote = 0.0174;
            Rate d7DQuote = 0.024;
    
            // swaps
            Rate s3mQuote = 0.0245875;
            Rate s6mQuote = 0.024600;
            Rate s9mQuote = 0.024600;
            Rate s1yQuote = 0.024750;
            Rate s2yQuote = 0.025150;
            Rate s3yQuote = 0.026110;
            Rate s4yQuote = 0.0272510;
            Rate s5yQuote = 0.028250;
            Rate s7yQuote = 0.029550;
            Rate s10yQuote = 0.03140;
    
            /********************
             ***    QUOTES    ***
             ********************/
    
            // deposits
            boost::shared_ptr<Quote> d1DRate(new SimpleQuote(d1DQuote));
            boost::shared_ptr<Quote> d7DRate(new SimpleQuote(d7DQuote));
    
            // swaps
            boost::shared_ptr<Quote> s3mRate(new SimpleQuote(s3mQuote));
            boost::shared_ptr<Quote> s6mRate(new SimpleQuote(s6mQuote));
            boost::shared_ptr<Quote> s9mRate(new SimpleQuote(s9mQuote));
            boost::shared_ptr<Quote> s1yRate(new SimpleQuote(s1yQuote));
            boost::shared_ptr<Quote> s2yRate(new SimpleQuote(s2yQuote));
            boost::shared_ptr<Quote> s3yRate(new SimpleQuote(s3yQuote));
            boost::shared_ptr<Quote> s4yRate(new SimpleQuote(s4yQuote));
            boost::shared_ptr<Quote> s5yRate(new SimpleQuote(s5yQuote));
            boost::shared_ptr<Quote> s7yRate(new SimpleQuote(s7yQuote));
            boost::shared_ptr<Quote> s10yRate(new SimpleQuote(s10yQuote));
    
            /*********************
             ***  RATE HELPERS ***
             *********************/
    
            // deposits
            DayCounter depositDayCounter = Actual365Fixed();
    
            boost::shared_ptr<RateHelper> d1D(new DepositRateHelper(Handle<Quote>(d1DRate), 1 * Days, fixingDays, calendar,
                                                                    ModifiedFollowing, false, depositDayCounter));
            boost::shared_ptr<RateHelper> d7D(new DepositRateHelper(Handle<Quote>(d7DRate), 7 * Days, fixingDays, calendar,
                                                                    ModifiedFollowing, false, depositDayCounter));
    
            // setup swaps
            Frequency swFixedLegFrequency = Quarterly;
            BusinessDayConvention swFixedLegConvention = ModifiedFollowing;
            DayCounter swFixedLegDayCounter = Actual365Fixed();
            boost::shared_ptr<IborIndex> swFloatingLegIndex(new CNYRepo7D);
    
            boost::shared_ptr<RateHelper> s3m(new SubPeriodsSwapHelper(Handle<Quote>(s3mRate),
                                                                       3 * Months, // SwapTenor
                                                                       3 * Months, // fixedTenor
                                                                       calendar, swFixedLegDayCounter, swFixedLegConvention,
                                                                       3 * Months, // floatpayTenor
                                                                       swFloatingLegIndex, swFixedLegDayCounter));
    
            boost::shared_ptr<RateHelper> s6m(new SubPeriodsSwapHelper(Handle<Quote>(s6mRate),
                                                                       6 * Months, // SwapTenor
                                                                       3 * Months, // fixedTenor
                                                                       calendar, swFixedLegDayCounter, swFixedLegConvention,
                                                                       3 * Months, // floatpayTenor
                                                                       swFloatingLegIndex, swFixedLegDayCounter));
    
            boost::shared_ptr<RateHelper> s9m(new SubPeriodsSwapHelper(Handle<Quote>(s9mRate),
                                                                       9 * Months, // SwapTenor
                                                                       3 * Months, // fixedTenor
                                                                       calendar, swFixedLegDayCounter, swFixedLegConvention,
                                                                       3 * Months, // floatpayTenor
                                                                       swFloatingLegIndex, swFixedLegDayCounter));
    
            boost::shared_ptr<RateHelper> s1y(new SubPeriodsSwapHelper(Handle<Quote>(s1yRate),
                                                                       1 * Years, // SwapTenor
                                                                       3 * Months, // fixedTenor
                                                                       calendar, swFixedLegDayCounter, swFixedLegConvention,
                                                                       3 * Months, // floatpayTenor
                                                                       swFloatingLegIndex, swFixedLegDayCounter));
    
            boost::shared_ptr<RateHelper> s2y(new SubPeriodsSwapHelper(Handle<Quote>(s2yRate),
                                                                       2 * Years,  // SwapTenor
                                                                       3 * Months, // fixedTenor
                                                                       calendar, swFixedLegDayCounter, swFixedLegConvention,
                                                                       3 * Months, // floatpayTenor
                                                                       swFloatingLegIndex, swFixedLegDayCounter));
    
            boost::shared_ptr<RateHelper> s3y(new SubPeriodsSwapHelper(Handle<Quote>(s3yRate),
                                                                       3 * Years,  // SwapTenor
                                                                       3 * Months, // fixedTenor
                                                                       calendar, swFixedLegDayCounter, swFixedLegConvention,
                                                                       3 * Months, // floatpayTenor
                                                                       swFloatingLegIndex, swFixedLegDayCounter));
    
            boost::shared_ptr<RateHelper> s4y(new SubPeriodsSwapHelper(Handle<Quote>(s4yRate),
                                                                       4 * Years,  // SwapTenor
                                                                       3 * Months, // fixedTenor
                                                                       calendar, swFixedLegDayCounter, swFixedLegConvention,
                                                                       3 * Months, // floatpayTenor
                                                                       swFloatingLegIndex, swFixedLegDayCounter));
    
            boost::shared_ptr<RateHelper> s5y(new SubPeriodsSwapHelper(Handle<Quote>(s5yRate),
                                                                       5 * Years,  // SwapTenor
                                                                       3 * Months, // fixedTenor
                                                                       calendar, swFixedLegDayCounter, swFixedLegConvention,
                                                                       3 * Months, // floatpayTenor
                                                                       swFloatingLegIndex, swFixedLegDayCounter));
    
            boost::shared_ptr<RateHelper> s7y(new SubPeriodsSwapHelper(Handle<Quote>(s7yRate),
                                                                       7 * Years,  // SwapTenor
                                                                       3 * Months, // fixedTenor
                                                                       calendar, swFixedLegDayCounter, swFixedLegConvention,
                                                                       3 * Months, // floatpayTenor
                                                                       swFloatingLegIndex, swFixedLegDayCounter));
    
            boost::shared_ptr<RateHelper> s10y(new SubPeriodsSwapHelper(Handle<Quote>(s10yRate),
                                                                       10 * Years, // SwapTenor
                                                                       3 * Months, // fixedTenor
                                                                       calendar, swFixedLegDayCounter, swFixedLegConvention,
                                                                       3 * Months, // floatpayTenor
                                                                       swFloatingLegIndex, swFixedLegDayCounter));
            /*********************
             **  CURVE BUILDING **
             *********************/
    
            DayCounter termStructureDayCounter = Actual365Fixed();
            double tolerance = 1.0e-15;
    
            // A depo-swap curve
            std::vector<boost::shared_ptr<RateHelper>> depoSwapInstruments;
            depoSwapInstruments.push_back(d1D);
            depoSwapInstruments.push_back(d7D);
            depoSwapInstruments.push_back(s3m);
            depoSwapInstruments.push_back(s6m);
            depoSwapInstruments.push_back(s9m);
            depoSwapInstruments.push_back(s1y);
            depoSwapInstruments.push_back(s2y);
            depoSwapInstruments.push_back(s3y);
            depoSwapInstruments.push_back(s4y);
            depoSwapInstruments.push_back(s5y);
            depoSwapInstruments.push_back(s7y);
            depoSwapInstruments.push_back(s10y);
    
            boost::shared_ptr<YieldTermStructure> depoSwapTermStructure(new PiecewiseYieldCurve<Discount, LogLinear>(
                valuationDate, 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;
    
            /*********************
             * SWAPS TO BE PRICED *
             **********************/
    
            // constant nominal 1,000,000 
            Real nominal = 1000000.0;
            Calendar cdr=China(China::IB);
            Integer lenghtInYears = 3;
            VanillaSwap::Type swapType = VanillaSwap::Payer;
            Date settlementDate(3, September, 2018);
            Date maturity = settlementDate + lenghtInYears * Years;
    
            // fixed leg
            Period fixedLegFrequency = 3 * Months;
            BusinessDayConvention fixedLegConvention = ModifiedFollowing;
            DayCounter fixedLegDayCounter = Actual365Fixed();
            Rate fixedRate = 0.02611;
    
            // floating leg
            Period floatingLegFrequency = 3 * Months;    
            BusinessDayConvention floatingLegConvention = ModifiedFollowing;
            DayCounter floatingLegDayCounter = Actual365Fixed();    
            boost::shared_ptr<IborIndex> cnyrepoIndex(new CNYRepo7D(forecastingTermStructure));
    
            cnyrepoIndex->addFixing(Date(30, November, 2018), 0.028);
            cnyrepoIndex->addFixing(Date(7, December, 2018), 0.0261);
            cnyrepoIndex->addFixing(Date(14, December, 2018), 0.028);
            cnyrepoIndex->addFixing(Date(21, December, 2018), 0.0263);
            cnyrepoIndex->addFixing(Date(30, December, 2018), 0.0296);
            cnyrepoIndex->addFixing(Date(4, January, 2019), 0.0248);
            cnyrepoIndex->addFixing(Date(11, January, 2019), 0.0253);
            cnyrepoIndex->addFixing(Date(18, January, 2019), 0.026);
            cnyrepoIndex->addFixing(Date(25, January, 2019), 0.026);
            cnyrepoIndex->addFixing(Date(3, February, 2019), 0.0233);
    
    	// Swap Object
            SubPeriodsSwap spot3YearSwap(settlementDate, nominal, lenghtInYears * Years, swapType == VanillaSwap::Payer,
    			                         fixedLegFrequency, fixedRate,
    			                         cdr, fixedLegDayCounter, fixedLegConvention,
                                                     floatingLegFrequency, cnyrepoIndex, floatingLegDayCounter, 
    			                         DateGeneration::Forward,
                                                     QuantExt::SubPeriodsCoupon::Compounding);
    
             /***************
             * 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 << "3-year market swap-rate = " << std::setprecision(4) << io::rate(s3yRate->value()) << std::endl;
            std::cout << dblrule << std::endl;
    
            std::cout << tab << "3-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=0.0;
    
            boost::shared_ptr<PricingEngine> swapEngine(new DiscountingSwapEngine(discountingTermStructure));
    
            spot3YearSwap.setPricingEngine(swapEngine);
    
            forecastingTermStructure.linkTo(depoSwapTermStructure);
            discountingTermStructure.linkTo(depoSwapTermStructure);
    		
            NPV = spot3YearSwap.NPV();
            fairSpread = spot3YearSwap.fairSpread();
            fairRate = spot3YearSwap.fairRate();
    
            std::cout << std::setw(headers[0].size()) << "depo-swap" << separator;
            std::cout << std::setw(headers[1].size()) << std::fixed << std::setprecision(4) << 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;
    
    		// I wanna change the three year swap rate and recalcualte the NPV and fairRate 
    		
            boost::shared_ptr<SimpleQuote> threeYearsRate = boost::dynamic_pointer_cast<SimpleQuote>(s3yRate);
            threeYearsRate->setValue(0.03);
    
            std::cout << dblrule << std::endl;
            std::cout << "3-year market swap-rate = " << io::rate(s3yRate->value()) << std::endl;
            std::cout << dblrule << std::endl;
    
            std::cout << tab << "3-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;
    
            forecastingTermStructure.linkTo(depoSwapTermStructure);
            discountingTermStructure.linkTo(depoSwapTermStructure);
    
            NPV = spot3YearSwap.NPV();
            fairSpread = spot3YearSwap.fairSpread();
            fairRate = spot3YearSwap.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;
            std::cout << rule << 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;
        }
    }

    //cnyrepo.cpp
    //=============================================================================================//

    #ifndef quantlib_cny_repo_hpp
    #define quantlib_cny_repo_hpp
    
    #include <ql/currencies/asia.hpp>
    #include <ql/time/calendars/china.hpp>
    #include <ql/time/daycounters/actual365fixed.hpp>
    
    namespace QuantLib {
    
    //! %CNY %Repo rate
    
    class CNYRepo : public IborIndex {
    public:
        CNYRepo(const Period& tenor, const Handle<YieldTermStructure>& h = Handle<YieldTermStructure>())
            : IborIndex("CNYRepo", tenor, 1, CNYCurrency(), China(China::IB), ModifiedFollowing, false, Actual365Fixed(),
                        h) {}
    };
    
    class CNYRepo7D : public CNYRepo {
    public:
        CNYRepo7D(const Handle<YieldTermStructure>& h = Handle<YieldTermStructure>()) : CNYRepo(Period(7, Days), h) {}
    };
    
    class CNYRepoON : public CNYRepo {
    public:
        CNYRepoON(const Handle<YieldTermStructure>& h = Handle<YieldTermStructure>()) : CNYRepo(Period(1, Days), h) {}
    };
    } // namespace QuantLib
    
    #endif
    #6641

    steve
    Participant

    Dear all,
    Really need your help. Any suggestion and direction is welcome. Many Thanks.

Viewing 2 posts - 1 through 2 (of 2 total)

You must be logged in to reply to this topic.