Пример #1
0
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())
                        );

}
Пример #2
0
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;
    }
}
Пример #4
0
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;
    }
}