Example #1
0
void SwapTest::testCachedValue() {

    BOOST_TEST_MESSAGE("Testing vanilla-swap calculation against cached value...");

    CommonVars vars;

    vars.today = Date(17,June,2002);
    Settings::instance().evaluationDate() = vars.today;
    vars.settlement =
        vars.calendar.advance(vars.today,vars.settlementDays,Days);
    vars.termStructure.linkTo(flatRate(vars.settlement,0.05,Actual365Fixed()));

    boost::shared_ptr<VanillaSwap> swap = vars.makeSwap(10, 0.06, 0.001);
    #ifndef QL_USE_INDEXED_COUPON
    Real cachedNPV   = -5.872863313209;
    #else
    Real cachedNPV   = -5.872342992212;
    #endif

    if (std::fabs(swap->NPV()-cachedNPV) > 1.0e-11)
        BOOST_ERROR("failed to reproduce cached swap value:\n"
                    << QL_FIXED << std::setprecision(12)
                    << "    calculated: " << swap->NPV() << "\n"
                    << "    expected:   " << cachedNPV);
}
void OvernightIndexedSwapTest::testSeasonedSwaps() {

    BOOST_TEST_MESSAGE("Testing seasoned Eonia-swap calculation...");

    CommonVars vars;

    Period lengths[] = { 1*Years, 2*Years, 5*Years, 10*Years, 20*Years };
    Spread spreads[] = { -0.001, -0.01, 0.0, 0.01, 0.001 };

    Date effectiveDate = Date(2, February, 2009);

    vars.eoniaIndex->addFixing(Date(2,February,2009), 0.0010); // fake fixing values
    vars.eoniaIndex->addFixing(Date(3,February,2009), 0.0011);
    vars.eoniaIndex->addFixing(Date(4,February,2009), 0.0012);
    vars.eoniaIndex->addFixing(Date(5,February,2009), 0.0013);

    for (Size i=0; i<LENGTH(lengths); i++) {
        for (Size j=0; j<LENGTH(spreads); j++) {

            shared_ptr<OvernightIndexedSwap> swap =
                vars.makeSwap(lengths[i],0.0,spreads[j],false,effectiveDate);
            shared_ptr<OvernightIndexedSwap> swap2 =
                vars.makeSwap(lengths[i],0.0,spreads[j],true,effectiveDate);
            if (std::fabs(swap->NPV() - swap2->NPV()) > 1.0e-10) {
                BOOST_ERROR("swap npv is different:\n"
                            << std::setprecision(2)
                            << "    length: " << lengths[i] << " \n"
                            << "    floating spread: "
                            << io::rate(spreads[j]) << "\n"
                            << "    swap value (non telescopic value dates): " << swap->NPV()
                            << "\n    swap value (telescopic value dates    ): " << swap2->NPV());
            }
        }
    }
}
Example #3
0
void SwapTest::testFairSpread() {

    BOOST_TEST_MESSAGE("Testing vanilla-swap calculation of "
                       "fair floating spread...");

    CommonVars vars;

    Integer lengths[] = { 1, 2, 5, 10, 20 };
    Rate rates[] = { 0.04, 0.05, 0.06, 0.07 };

    for (Size i=0; i<LENGTH(lengths); i++) {
        for (Size j=0; j<LENGTH(rates); j++) {

            boost::shared_ptr<VanillaSwap> swap =
                vars.makeSwap(lengths[i],rates[j],0.0);
            swap = vars.makeSwap(lengths[i],rates[j],swap->fairSpread());
            if (std::fabs(swap->NPV()) > 1.0e-10) {
                BOOST_ERROR("recalculating with implied spread:\n"
                            << std::setprecision(2)
                            << "    length: " << lengths[i] << " years\n"
                            << "    fixed rate: " << io::rate(rates[j]) << "\n"
                            << "    swap value: " << swap->NPV());
            }
        }
    }
}
Example #4
0
void CapFloorTest::testATMRate() {

    BOOST_TEST_MESSAGE("Testing cap/floor ATM rate...");

    CommonVars vars;

    Integer lengths[] = { 1, 2, 3, 5, 7, 10, 15, 20 };
    Rate strikes[] = { 0., 0.03, 0.04, 0.05, 0.06, 0.07 };
    Volatility vols[] = { 0.01, 0.05, 0.10, 0.15, 0.20 };

    Date startDate = vars.termStructure->referenceDate();

    for (Size i=0; i<LENGTH(lengths); i++) {
        Leg leg = vars.makeLeg(startDate,lengths[i]);
        Date maturity = vars.calendar.advance(startDate,lengths[i],Years,
                                  vars.convention);
        Schedule schedule(startDate,maturity,
                          Period(vars.frequency),vars.calendar,
                          vars.convention,vars.convention,
                          DateGeneration::Forward,false);

        for (Size j=0; j<LENGTH(strikes); j++) {
            for (Size k=0; k<LENGTH(vols); k++) {
                boost::shared_ptr<CapFloor> cap =
                    vars.makeCapFloor(CapFloor::Cap, leg, strikes[j],vols[k]);
                boost::shared_ptr<CapFloor> floor =
                    vars.makeCapFloor(CapFloor::Floor, leg, strikes[j],vols[k]);
                Rate capATMRate = cap->atmRate(**vars.termStructure);
                Rate floorATMRate = floor->atmRate(**vars.termStructure);
                if (!checkAbsError(floorATMRate, capATMRate, 1.0e-10))
                    BOOST_FAIL(
                      "Cap ATM Rate and floor ATM Rate should be equal :\n"
                      << "   length:        " << lengths[i] << " years\n"
                      << "   volatility:    " << io::volatility(vols[k]) << "\n"
                      << "   strike:        " << io::rate(strikes[j]) << "\n"
                      << "   cap ATM rate:  " << capATMRate << "\n"
                      << "   floor ATM rate:" << floorATMRate << "\n"
                      << "   relative Error:"
                      << relativeError(capATMRate, floorATMRate,
                                       capATMRate)*100 << "%" );
                VanillaSwap swap(VanillaSwap::Payer, vars.nominals[0],
                                 schedule, floorATMRate,
                                 vars.index->dayCounter(),
                                 schedule, vars.index, 0.0,
                                 vars.index->dayCounter());
                swap.setPricingEngine(boost::shared_ptr<PricingEngine>(
                              new DiscountingSwapEngine(vars.termStructure)));
                Real swapNPV = swap.NPV();
                if (!checkAbsError(swapNPV, 0, 1.0e-10))
                    BOOST_FAIL(
                      "the NPV of a Swap struck at ATM rate "
                      "should be equal to 0:\n"
                      << "   length:        " << lengths[i] << " years\n"
                      << "   volatility:    " << io::volatility(vols[k]) << "\n"
                      << "   ATM rate:      " << io::rate(floorATMRate) << "\n"
                      << "   swap NPV:      " << swapNPV);
        }
      }
    }
}
Example #5
0
void OptionletStripperTest::testFlatTermVolatilityStripping1() {

    BOOST_TEST_MESSAGE(
        "Testing forward/forward vol stripping from flat term vol "
        "surface using OptionletStripper1 class...");

    CommonVars vars;
    Settings::instance().evaluationDate() = Date(28, October, 2013);

    vars.setFlatTermVolSurface();

    shared_ptr<IborIndex> iborIndex(new Euribor6M(vars.yieldTermStructure));

    boost::shared_ptr<OptionletStripper> optionletStripper1(new
        OptionletStripper1(vars.flatTermVolSurface,
                           iborIndex,
                           Null<Rate>(),
                           vars.accuracy));

    boost::shared_ptr<StrippedOptionletAdapter> strippedOptionletAdapter(new
        StrippedOptionletAdapter(optionletStripper1));

    Handle<OptionletVolatilityStructure> vol(strippedOptionletAdapter);

    vol->enableExtrapolation();

    boost::shared_ptr<BlackCapFloorEngine> strippedVolEngine(new
        BlackCapFloorEngine(vars.yieldTermStructure,
                            vol));

    boost::shared_ptr<CapFloor> cap;
    for (Size tenorIndex=0; tenorIndex<vars.optionTenors.size(); ++tenorIndex) {
        for (Size strikeIndex=0; strikeIndex<vars.strikes.size(); ++strikeIndex) {
            cap = MakeCapFloor(CapFloor::Cap,
                               vars.optionTenors[tenorIndex],
                               iborIndex,
                               vars.strikes[strikeIndex],
                               0*Days)
                  .withPricingEngine(strippedVolEngine);

            Real priceFromStrippedVolatility = cap->NPV();

            boost::shared_ptr<PricingEngine> blackCapFloorEngineConstantVolatility(new
                BlackCapFloorEngine(vars.yieldTermStructure,
                                    vars.termV[tenorIndex][strikeIndex]));

            cap->setPricingEngine(blackCapFloorEngineConstantVolatility);
            Real priceFromConstantVolatility = cap->NPV();

            Real error = std::fabs(priceFromStrippedVolatility - priceFromConstantVolatility);
            if (error>vars.tolerance)
                BOOST_FAIL("\noption tenor:       " << vars.optionTenors[tenorIndex] <<
                           "\nstrike:             " << io::rate(vars.strikes[strikeIndex]) <<
                           "\nstripped vol price: " << io::rate(priceFromStrippedVolatility) <<
                           "\nconstant vol price: " << io::rate(priceFromConstantVolatility) <<
                           "\nerror:              " << io::rate(error) <<
                           "\ntolerance:          " << io::rate(vars.tolerance));
            }
    }
}
Example #6
0
void OvernightIndexedSwapTest::testFairSpread() {

    BOOST_TEST_MESSAGE("Testing Eonia-swap calculation of "
                       "fair floating spread...");

    CommonVars vars;

    Period lengths[] = { 1*Years, 2*Years, 5*Years, 10*Years, 20*Years };
    Rate rates[] = { 0.04, 0.05, 0.06, 0.07 };

    for (Size i=0; i<LENGTH(lengths); i++) {
        for (Size j=0; j<LENGTH(rates); j++) {

            shared_ptr<OvernightIndexedSwap> swap =
                vars.makeSwap(lengths[i], rates[j], 0.0);
            Spread fairSpread = swap->fairSpread();
            swap = vars.makeSwap(lengths[i], rates[j], fairSpread);

            if (std::fabs(swap->NPV()) > 1.0e-10) {
                BOOST_ERROR("\nrecalculating with implied spread:" <<
                            std::setprecision(2) <<
                            "\n     length: " << lengths[i] <<
                            "\n fixed rate: " << io::rate(rates[j]) <<
                            "\nfair spread: " << io::rate(fairSpread) <<
                            "\n swap value: " << swap->NPV());
            }
        }
    }

}
Example #7
0
void OvernightIndexedSwapTest::testFairRate() {

    BOOST_TEST_MESSAGE("Testing Eonia-swap calculation of fair fixed rate...");

    CommonVars vars;

    Period lengths[] = { 1*Years, 2*Years, 5*Years, 10*Years, 20*Years };
    Spread spreads[] = { -0.001, -0.01, 0.0, 0.01, 0.001 };

    for (Size i=0; i<LENGTH(lengths); i++) {
        for (Size j=0; j<LENGTH(spreads); j++) {

            shared_ptr<OvernightIndexedSwap> swap =
                vars.makeSwap(lengths[i],0.0,spreads[j]);
            swap = vars.makeSwap(lengths[i],swap->fairRate(),spreads[j]);
            if (std::fabs(swap->NPV()) > 1.0e-10) {
                BOOST_ERROR("recalculating with implied rate:\n"
                            << std::setprecision(2)
                            << "    length: " << lengths[i] << " \n"
                            << "    floating spread: "
                            << io::rate(spreads[j]) << "\n"
                            << "    swap value: " << swap->NPV());
            }
        }
    }
}
void OvernightIndexedSwapTest::testCachedValue() {

    BOOST_TEST_MESSAGE("Testing Eonia-swap calculation against cached value...");

    CommonVars vars;

    Settings::instance().evaluationDate() = vars.today;
    vars.settlement =
        vars.calendar.advance(vars.today,vars.settlementDays,Days);
    Real flat = 0.05;
    vars.eoniaTermStructure.linkTo(flatRate(vars.settlement,flat,Actual360()));
    Real fixedRate = exp(flat) - 1;
    shared_ptr<OvernightIndexedSwap> swap = vars.makeSwap(1*Years, fixedRate, 0.0,false);
    shared_ptr<OvernightIndexedSwap> swap2 = vars.makeSwap(1*Years, fixedRate, 0.0,true);
    Real cachedNPV   = 0.001730450147;
    Real tolerance = 1.0e-11;
    if (std::fabs(swap->NPV()-cachedNPV) > tolerance)
        BOOST_ERROR("\nfailed to reproduce cached swap value (non telescopic value dates):" <<
                    std::fixed << std::setprecision(12) <<
                    "\ncalculated: " << swap->NPV() <<
                    "\n  expected: " << cachedNPV <<
                    "\n tolerance:" << tolerance);
    if (std::fabs(swap2->NPV()-cachedNPV) > tolerance)
        BOOST_ERROR("\nfailed to reproduce cached swap value (telescopic value dates):" <<
                    std::fixed << std::setprecision(12) <<
                    "\ncalculated: " << swap->NPV() <<
                    "\n  expected: " << cachedNPV <<
                    "\n tolerance:" << tolerance);
}
Example #9
0
void SwaptionTest::testCachedValue() {

    BOOST_MESSAGE("Testing swaption value against cached value...");

    CommonVars vars;

    vars.today = Date(13, March, 2002);
    vars.settlement = Date(15, March, 2002);
    Settings::instance().evaluationDate() = vars.today;
    vars.termStructure.linkTo(flatRate(vars.settlement, 0.05, Actual365Fixed()));
    Date exerciseDate = vars.calendar.advance(vars.settlement, 5*Years);
    Date startDate = vars.calendar.advance(exerciseDate,
                                           vars.settlementDays, Days);
    boost::shared_ptr<VanillaSwap> swap =
        MakeVanillaSwap(10*Years, vars.index, 0.06)
        .withEffectiveDate(startDate);

    boost::shared_ptr<Swaption> swaption =
        vars.makeSwaption(swap, exerciseDate, 0.20);
    #ifndef QL_USE_INDEXED_COUPON
    Real cachedNPV = 0.036418158579;
    #else
    Real cachedNPV = 0.036421429684;
    #endif

    // FLOATING_POINT_EXCEPTION
    if (std::fabs(swaption->NPV()-cachedNPV) > 1.0e-12)
        BOOST_ERROR("failed to reproduce cached swaption value:\n" <<
                    QL_FIXED << std::setprecision(12) <<
                    "\ncalculated: " << swaption->NPV() <<
                    "\nexpected:   " << cachedNPV);
}
void SwaptionVolatilityMatrixTest::testSwaptionVolMatrixCoherence() {

    BOOST_TEST_MESSAGE("Testing swaption volatility matrix...");

    CommonVars vars;

    boost::shared_ptr<SwaptionVolatilityMatrix> vol;
    std::string description;

    //floating reference date, floating market data
    description = "floating reference date, floating market data";
    vol = boost::shared_ptr<SwaptionVolatilityMatrix>(new
        SwaptionVolatilityMatrix(vars.conventions.calendar,
                                 vars.conventions.optionBdc,
                                 vars.atm.tenors.options,
                                 vars.atm.tenors.swaps,
                                 vars.atm.volsHandle,
                                 vars.conventions.dayCounter));
    vars.makeCoherenceTest(description, vol);

    //fixed reference date, floating market data
    description = "fixed reference date, floating market data";
    vol = boost::shared_ptr<SwaptionVolatilityMatrix>(new
        SwaptionVolatilityMatrix(Settings::instance().evaluationDate(),
                                 vars.conventions.calendar,
                                 vars.conventions.optionBdc,
                                 vars.atm.tenors.options,
                                 vars.atm.tenors.swaps,
                                 vars.atm.volsHandle,
                                 vars.conventions.dayCounter));
    vars.makeCoherenceTest(description, vol);

    // floating reference date, fixed market data
    description = "floating reference date, fixed market data";
    vol = boost::shared_ptr<SwaptionVolatilityMatrix>(new
        SwaptionVolatilityMatrix(vars.conventions.calendar,
                                 vars.conventions.optionBdc,
                                 vars.atm.tenors.options,
                                 vars.atm.tenors.swaps,
                                 vars.atm.volsHandle,
                                 vars.conventions.dayCounter));
    vars.makeCoherenceTest(description, vol);

    // fixed reference date, fixed market data
    description = "fixed reference date, fixed market data";
    vol = boost::shared_ptr<SwaptionVolatilityMatrix>(new
        SwaptionVolatilityMatrix(Settings::instance().evaluationDate(),
                                 vars.conventions.calendar,
                                 vars.conventions.optionBdc,
                                 vars.atm.tenors.options,
                                 vars.atm.tenors.swaps,
                                 vars.atm.volsHandle,
                                 vars.conventions.dayCounter));
    vars.makeCoherenceTest(description, vol);
}
Example #11
0
void CapFloorTest::testVega() {

    BOOST_TEST_MESSAGE("Testing cap/floor vega...");

    CommonVars vars;

    Integer lengths[] = { 1, 2, 3, 4, 5, 6, 7, 10, 15, 20, 30 };
    Volatility vols[] = { 0.01, 0.05, 0.10, 0.15, 0.20 };
    Rate strikes[] = { 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09 };
    CapFloor::Type types[] = { CapFloor::Cap, CapFloor::Floor};

    Date startDate = vars.termStructure->referenceDate();
    static const Real shift = 1e-8;
    static const Real tolerance = 0.005;

    for (Size i=0; i<LENGTH(lengths); i++) {
        for (Size j=0; j<LENGTH(vols); j++) {
            for (Size k=0; k<LENGTH(strikes); k++) {
                for (Size h=0; h<LENGTH(types); h++) {
                    Leg leg = vars.makeLeg(startDate, lengths[i]);
                    boost::shared_ptr<CapFloor> capFloor =
                        vars.makeCapFloor(types[h],leg,
                                          strikes[k],vols[j]);
                    boost::shared_ptr<CapFloor> shiftedCapFloor2 =
                        vars.makeCapFloor(types[h],leg,
                                          strikes[k],vols[j]+shift);
                     boost::shared_ptr<CapFloor> shiftedCapFloor1 =
                        vars.makeCapFloor(types[h],leg,
                                          strikes[k],vols[j]-shift);
                    Real value1 = shiftedCapFloor1->NPV();
                    Real value2 = shiftedCapFloor2->NPV();
                    Real numericalVega = (value2 - value1) / (2*shift);
                    if (numericalVega>1.0e-4) {
                        Real analyticalVega = capFloor->result<Real>("vega");
                        Real discrepancy =
                            std::fabs(numericalVega - analyticalVega);
                        discrepancy /= numericalVega;
                        if (discrepancy > tolerance)
                            BOOST_FAIL(
                                "failed to compute cap/floor vega:" <<
                                "\n   lengths:     " << lengths[j]*Years <<
                                "\n   strike:      " << io::rate(strikes[k]) <<
                                //"\n   types:       " << types[h] <<
                                QL_FIXED << std::setprecision(12) <<
                                "\n   calculated:  " << analyticalVega <<
                                "\n   expected:    " << numericalVega <<
                                "\n   discrepancy: " << io::rate(discrepancy) <<
                                "\n   tolerance:   " << io::rate(tolerance));
                     }
                }
            }
        }
    }
}
Example #12
0
void OptionletStripperTest::testSwitchStrike() {
    BOOST_TEST_MESSAGE("Testing switch strike level and recalibration of level "
                       "in case of curve relinking...");

    CommonVars vars;
    Settings::instance().evaluationDate() = Date(28, October, 2013);
    vars.setCapFloorTermVolSurface();

    RelinkableHandle< YieldTermStructure > yieldTermStructure;
    yieldTermStructure.linkTo(boost::shared_ptr< FlatForward >(
        new FlatForward(0, vars.calendar, 0.03, vars.dayCounter)));

    shared_ptr< IborIndex > iborIndex(new Euribor6M(yieldTermStructure));

    boost::shared_ptr< OptionletStripper1 > optionletStripper1(
        new OptionletStripper1(vars.capFloorVolSurface, iborIndex,
                               Null< Rate >(), vars.accuracy));


    #if defined(QL_USE_INDEXED_COUPON)
    Real expected = 0.02981258;
    #else
    Real expected = 0.02981223;
    #endif

    Real error = std::fabs(optionletStripper1->switchStrike() - expected);
    if (error > vars.tolerance)
        BOOST_FAIL("\nSwitchstrike not correctly computed:  "
                   << "\nexpected switch strike: " << io::rate(expected)
                   << "\ncomputed switch strike: "
                   << io::rate(optionletStripper1->switchStrike())
                   << "\nerror:         " << io::rate(error)
                   << "\ntolerance:     " << io::rate(vars.tolerance));

    yieldTermStructure.linkTo(boost::shared_ptr< FlatForward >(
        new FlatForward(0, vars.calendar, 0.05, vars.dayCounter)));

    #if defined(QL_USE_INDEXED_COUPON)
    expected = 0.0499381;
    #else
    expected = 0.0499371;
    #endif

    error = std::fabs(optionletStripper1->switchStrike() - expected);
    if (error > vars.tolerance)
        BOOST_FAIL("\nSwitchstrike not correctly computed:  "
                   << "\nexpected switch strike: " << io::rate(expected)
                   << "\ncomputed switch strike: "
                   << io::rate(optionletStripper1->switchStrike())
                   << "\nerror:         " << io::rate(error)
                   << "\ntolerance:     " << io::rate(vars.tolerance));
}
Example #13
0
void CapFloorTest::testParity() {

    BOOST_TEST_MESSAGE("Testing cap/floor parity...");

    CommonVars vars;

    Integer lengths[] = { 1, 2, 3, 5, 7, 10, 15, 20 };
    Rate strikes[] = { 0., 0.03, 0.04, 0.05, 0.06, 0.07 };
    Volatility vols[] = { 0.01, 0.05, 0.10, 0.15, 0.20 };

    Date startDate = vars.termStructure->referenceDate();

    for (Size i=0; i<LENGTH(lengths); i++) {
      for (Size j=0; j<LENGTH(strikes); j++) {
        for (Size k=0; k<LENGTH(vols); k++) {

            Leg leg = vars.makeLeg(startDate,lengths[i]);
            boost::shared_ptr<Instrument> cap =
                vars.makeCapFloor(CapFloor::Cap,leg,
                                  strikes[j],vols[k]);
            boost::shared_ptr<Instrument> floor =
                vars.makeCapFloor(CapFloor::Floor,leg,
                                  strikes[j],vols[k]);
            Date maturity = vars.calendar.advance(startDate,lengths[i],Years,
                                              vars.convention);
            Schedule schedule(startDate,maturity,
                              Period(vars.frequency),vars.calendar,
                              vars.convention,vars.convention,
                              DateGeneration::Forward,false);
            VanillaSwap swap(VanillaSwap::Payer, vars.nominals[0],
                             schedule, strikes[j], vars.index->dayCounter(),
                             schedule, vars.index, 0.0,
                             vars.index->dayCounter());
            swap.setPricingEngine(boost::shared_ptr<PricingEngine>(
                              new DiscountingSwapEngine(vars.termStructure)));
            // FLOATING_POINT_EXCEPTION
            if (std::fabs((cap->NPV()-floor->NPV()) - swap.NPV()) > 1.0e-10) {
                BOOST_FAIL(
                    "put/call parity violated:\n"
                    << "    length:      " << lengths[i] << " years\n"
                    << "    volatility:  " << io::volatility(vols[k]) << "\n"
                    << "    strike:      " << io::rate(strikes[j]) << "\n"
                    << "    cap value:   " << cap->NPV() << "\n"
                    << "    floor value: " << floor->NPV() << "\n"
                    << "    swap value:  " << swap.NPV());
            }
        }
      }
    }
}
Example #14
0
void CapFloorTest::testCachedValue() {

    BOOST_TEST_MESSAGE("Testing Black cap/floor price against cached values...");

    CommonVars vars;

    Date cachedToday(14,March,2002),
         cachedSettlement(18,March,2002);
    Settings::instance().evaluationDate() = cachedToday;
    vars.termStructure.linkTo(flatRate(cachedSettlement, 0.05, Actual360()));
    Date startDate = vars.termStructure->referenceDate();
    Leg leg = vars.makeLeg(startDate,20);
    boost::shared_ptr<Instrument> cap = vars.makeCapFloor(CapFloor::Cap,leg,
                                                          0.07,0.20);
    boost::shared_ptr<Instrument> floor = vars.makeCapFloor(CapFloor::Floor,leg,
                                                            0.03,0.20);
#ifndef QL_USE_INDEXED_COUPON
    // par coupon price
    Real cachedCapNPV   = 6.87570026732,
         cachedFloorNPV = 2.65812927959;
#else
    // index fixing price
    Real cachedCapNPV   = 6.87630307745,
         cachedFloorNPV = 2.65796764715;
#endif
    // test Black cap price against cached value
    if (std::fabs(cap->NPV()-cachedCapNPV) > 1.0e-11)
        BOOST_ERROR(
            "failed to reproduce cached cap value:\n"
            << std::setprecision(12)
            << "    calculated: " << cap->NPV() << "\n"
            << "    expected:   " << cachedCapNPV);
    // test Black floor price against cached value
    if (std::fabs(floor->NPV()-cachedFloorNPV) > 1.0e-11)
        BOOST_ERROR(
            "failed to reproduce cached floor value:\n"
            << std::setprecision(12)
            << "    calculated: " << floor->NPV() << "\n"
            << "    expected:   " << cachedFloorNPV);
}
Example #15
0
void SwapTest::testSpreadDependency() {

    BOOST_TEST_MESSAGE("Testing vanilla-swap dependency on floating spread...");

    CommonVars vars;

    Integer lengths[] = { 1, 2, 5, 10, 20 };
    Rate rates[] = { 0.04, 0.05, 0.06, 0.07 };
    Spread spreads[] = { -0.01, -0.002, -0.001, 0.0, 0.001, 0.002, 0.01 };

    for (Size i=0; i<LENGTH(lengths); i++) {
        for (Size j=0; j<LENGTH(rates); j++) {
            // store the results for different spreads...
            std::vector<Real> swap_values;
            for (Size k=0; k<LENGTH(spreads); k++) {
                boost::shared_ptr<VanillaSwap> swap =
                    vars.makeSwap(lengths[i],rates[j],spreads[k]);
                swap_values.push_back(swap->NPV());
            }
            // and check that they go the right way
            std::vector<Real>::iterator it =
                std::adjacent_find(swap_values.begin(),swap_values.end(),
                                   std::greater<Real>());
            if (it != swap_values.end()) {
                Size n = it - swap_values.begin();
                BOOST_ERROR(
                    "NPV is decreasing with the floating spread in a swap: \n"
                    << "    length: " << lengths[i] << " years\n"
                    << "    value:  " << swap_values[n]
                    << " receiving spread: " << io::rate(spreads[n]) << "\n"
                    << "    value:  " << swap_values[n+1]
                    << " receiving spread: " << io::rate(spreads[n+1]));
            }
        }
    }
}
double in_arrear_floorlet(const Date& todaysDate_,
	double start,
	double length,
	Rate spot_,
	Rate strike,
	Volatility volatility
	)
{
	CommonVars vars;

	try{
		vars.makeIndex(todaysDate_,spot_);
	
		Leg leg = vars.makeLeg(start,length);

		boost::shared_ptr<Instrument> floor = vars.makeCapFloor(CapFloor::Floor, leg, strike, volatility);
	
		return floor->NPV();
	}
	catch (std::exception& e) {
		std::cerr << e.what() << std::endl;
		return 1;
	}
}
Example #17
0
void CapFloorTest::testImpliedVolatility() {

    BOOST_TEST_MESSAGE("Testing implied term volatility for cap and floor...");

    CommonVars vars;

    Size maxEvaluations = 100;
    Real tolerance = 1.0e-8;

    CapFloor::Type types[] = { CapFloor::Cap, CapFloor::Floor };
    Rate strikes[] = { 0.02, 0.03, 0.04 };
    Integer lengths[] = { 1, 5, 10 };

    // test data
    Rate rRates[] = { 0.02, 0.03, 0.04, 0.05, 0.06, 0.07 };
    Volatility vols[] = { 0.01, 0.05, 0.10, 0.20, 0.30, 0.70, 0.90 };

    for (Size k=0; k<LENGTH(lengths); k++) {
        Leg leg = vars.makeLeg(vars.settlement, lengths[k]);

        for (Size i=0; i<LENGTH(types); i++) {
            for (Size j=0; j<LENGTH(strikes); j++) {

                boost::shared_ptr<CapFloor> capfloor =
                    vars.makeCapFloor(types[i], leg, strikes[j], 0.0);

                for (Size n=0; n<LENGTH(rRates); n++) {
                    for (Size m=0; m<LENGTH(vols); m++) {

                        Rate r = rRates[n];
                        Volatility v = vols[m];
                        vars.termStructure.linkTo(flatRate(vars.settlement,r,
                                                       Actual360()));
                        capfloor->setPricingEngine(vars.makeEngine(v));

                        Real value = capfloor->NPV();
                        Volatility implVol = 0.0;
                        try {
                            implVol =
                                capfloor->impliedVolatility(value,
                                                            vars.termStructure,
                                                            0.10,
                                                            tolerance,
                                                            maxEvaluations,
                                                            10.0e-7, 4.0, 0.0);
                        } catch (std::exception& e) {
                            // couldn't bracket?
                            capfloor->setPricingEngine(vars.makeEngine(0.0));
                            Real value2 = capfloor->NPV();
                            if (std::fabs(value-value2) < tolerance) {
                                // ok, just skip:
                                continue;
                            }
                            // otherwise, report error
                            BOOST_ERROR("implied vol failure: " <<
                                        typeToString(types[i]) <<
                                        "\n  strike:     " << io::rate(strikes[j]) <<
                                        "\n  risk-free:  " << io::rate(r) <<
                                        "\n  length:     " << lengths[k] << "Y" <<
                                        "\n  volatility: " << io::volatility(v) <<
                                        "\n  price:      " << value <<
                                        "\n" << e.what());
                        }
                        if (std::fabs(implVol-v) > tolerance) {
                            // the difference might not matter
                            capfloor->setPricingEngine(
                                                    vars.makeEngine(implVol));
                            Real value2 = capfloor->NPV();
                            if (std::fabs(value-value2) > tolerance) {
                            BOOST_FAIL("implied vol failure: " <<
                                       typeToString(types[i]) <<
                                       "\n  strike:        " << io::rate(strikes[j]) <<
                                       "\n  risk-free:     " << io::rate(r) <<
                                       "\n  length:        " << lengths[k] << "Y" <<
                                       "\n  volatility:    " << io::volatility(v) <<
                                       "\n  price:         " << value <<
                                       "\n  implied vol:   " << io::volatility(implVol) <<
                                       "\n  implied price: " << value2);
                            }
                        }
                    }
                }
            }
        }
    }
}
Example #18
0
void SwaptionTest::testCashSettledSwaptions() {

    BOOST_MESSAGE("Testing cash settled swaptions modified annuity...");

    CommonVars vars;

    Rate strike = 0.05;

    for (Size i=0; i<LENGTH(exercises); i++) {
        for (Size j=0; j<LENGTH(lengths); j++) {

            Date exerciseDate = vars.calendar.advance(vars.today,exercises[i]);
            Date startDate = vars.calendar.advance(exerciseDate,
                                                   vars.settlementDays,Days);
            Date maturity =
                vars.calendar.advance(startDate,lengths[j],
                                      vars.floatingConvention);
            Schedule floatSchedule(startDate, maturity, vars.floatingTenor,
                                   vars.calendar,vars.floatingConvention,
                                   vars.floatingConvention,
                                   DateGeneration::Forward, false);
            // Swap with fixed leg conventions: Business Days = Unadjusted, DayCount = 30/360
            Schedule fixedSchedule_u(startDate, maturity,
                                     Period(vars.fixedFrequency),
                                     vars.calendar, Unadjusted, Unadjusted,
                                     DateGeneration::Forward, true);
            boost::shared_ptr<VanillaSwap> swap_u360(
                new VanillaSwap(type[0], vars.nominal,
                                fixedSchedule_u,strike,Thirty360(),
                                floatSchedule,vars.index,0.0,
                                vars.index->dayCounter()));

            // Swap with fixed leg conventions: Business Days = Unadjusted, DayCount = Act/365
            boost::shared_ptr<VanillaSwap> swap_u365(
                new VanillaSwap(type[0],vars.nominal,
                                fixedSchedule_u,strike,Actual365Fixed(),
                                floatSchedule,vars.index,0.0,
                                vars.index->dayCounter()));

            // Swap with fixed leg conventions: Business Days = Modified Following, DayCount = 30/360
            Schedule fixedSchedule_a(startDate,maturity,
                                     Period(vars.fixedFrequency),
                                     vars.calendar,ModifiedFollowing,
                                     ModifiedFollowing,
                                     DateGeneration::Forward, true);
            boost::shared_ptr<VanillaSwap> swap_a360(
                new VanillaSwap(type[0],vars.nominal,
                                fixedSchedule_a,strike,Thirty360(),
                                floatSchedule,vars.index,0.0,
                                vars.index->dayCounter()));

            // Swap with fixed leg conventions: Business Days = Modified Following, DayCount = Act/365
            boost::shared_ptr<VanillaSwap> swap_a365(
                new VanillaSwap(type[0],vars.nominal,
                                fixedSchedule_a,strike,Actual365Fixed(),
                                floatSchedule,vars.index,0.0,
                                vars.index->dayCounter()));

            boost::shared_ptr<PricingEngine> swapEngine(
                               new DiscountingSwapEngine(vars.termStructure));

            swap_u360->setPricingEngine(swapEngine);
            swap_a360->setPricingEngine(swapEngine);
            swap_u365->setPricingEngine(swapEngine);
            swap_a365->setPricingEngine(swapEngine);

            const Leg& swapFixedLeg_u360 = swap_u360->fixedLeg();
            const Leg& swapFixedLeg_a360 = swap_a360->fixedLeg();
            const Leg& swapFixedLeg_u365 = swap_u365->fixedLeg();
            const Leg& swapFixedLeg_a365 = swap_a365->fixedLeg();

            // FlatForward curves
            // FLOATING_POINT_EXCEPTION
            Handle<YieldTermStructure> termStructure_u360(
                boost::shared_ptr<YieldTermStructure>(
                    new FlatForward(vars.settlement,swap_u360->fairRate(),
                                    Thirty360(),Compounded,
                                    vars.fixedFrequency)));
            Handle<YieldTermStructure> termStructure_a360(
                boost::shared_ptr<YieldTermStructure>(
                    new FlatForward(vars.settlement,swap_a360->fairRate(),
                                    Thirty360(),Compounded,
                                    vars.fixedFrequency)));
            Handle<YieldTermStructure> termStructure_u365(
                boost::shared_ptr<YieldTermStructure>(
                    new FlatForward(vars.settlement,swap_u365->fairRate(),
                                    Actual365Fixed(),Compounded,
                                    vars.fixedFrequency)));
            Handle<YieldTermStructure> termStructure_a365(
                boost::shared_ptr<YieldTermStructure>(
                    new FlatForward(vars.settlement,swap_a365->fairRate(),
                                    Actual365Fixed(),Compounded,
                                    vars.fixedFrequency)));

            // Annuity calculated by swap method fixedLegBPS().
            // Fixed leg conventions: Unadjusted, 30/360
            Real annuity_u360 = swap_u360->fixedLegBPS() / 0.0001;
            annuity_u360 = swap_u360->type()==VanillaSwap::Payer ?
                -annuity_u360 : annuity_u360;
            // Fixed leg conventions: ModifiedFollowing, act/365
            Real annuity_a365 = swap_a365->fixedLegBPS() / 0.0001;
            annuity_a365 = swap_a365->type()==VanillaSwap::Payer ?
                -annuity_a365 : annuity_a365;
            // Fixed leg conventions: ModifiedFollowing, 30/360
            Real annuity_a360 = swap_a360->fixedLegBPS() / 0.0001;
            annuity_a360 = swap_a360->type()==VanillaSwap::Payer ?
                -annuity_a360 : annuity_a360;
            // Fixed leg conventions: Unadjusted, act/365
            Real annuity_u365 = swap_u365->fixedLegBPS() / 0.0001;
            annuity_u365 = swap_u365->type()==VanillaSwap::Payer ?
                -annuity_u365 : annuity_u365;

            // Calculation of Modified Annuity (cash settlement)
            // Fixed leg conventions of swap: unadjusted, 30/360
            Real cashannuity_u360 = 0.;
            Size i;
            for (i=0; i<swapFixedLeg_u360.size(); i++) {
                cashannuity_u360 += swapFixedLeg_u360[i]->amount()/strike
                                  * termStructure_u360->discount(
                                    swapFixedLeg_u360[i]->date());
            }
            // Fixed leg conventions of swap: unadjusted, act/365
            Real cashannuity_u365 = 0.;
            for (i=0; i<swapFixedLeg_u365.size(); i++) {
                cashannuity_u365 += swapFixedLeg_u365[i]->amount()/strike
                                  * termStructure_u365->discount(
                                    swapFixedLeg_u365[i]->date());
            }
            // Fixed leg conventions of swap: modified following, 30/360
            Real cashannuity_a360 = 0.;
            for (i=0; i<swapFixedLeg_a360.size(); i++) {
                cashannuity_a360 += swapFixedLeg_a360[i]->amount()/strike
                                  * termStructure_a360->discount(
                                    swapFixedLeg_a360[i]->date());
            }
            // Fixed leg conventions of swap: modified following, act/365
            Real cashannuity_a365 = 0.;
            for (i=0; i<swapFixedLeg_a365.size(); i++) {
                cashannuity_a365 += swapFixedLeg_a365[i]->amount()/strike
                                  * termStructure_a365->discount(
                                    swapFixedLeg_a365[i]->date());
            }

            // Swaptions: underlying swap fixed leg conventions:
            // unadjusted, 30/360

            // Physical settled swaption
            boost::shared_ptr<Swaption> swaption_p_u360 =
                vars.makeSwaption(swap_u360,exerciseDate,0.20);
            Real value_p_u360 = swaption_p_u360->NPV();
            // Cash settled swaption
            boost::shared_ptr<Swaption> swaption_c_u360 =
                vars.makeSwaption(swap_u360,exerciseDate,0.20,
                                  Settlement::Cash);
            Real value_c_u360 = swaption_c_u360->NPV();
            // the NPV's ratio must be equal to annuities ratio
            Real npv_ratio_u360 = value_c_u360 / value_p_u360;
            Real annuity_ratio_u360 = cashannuity_u360 / annuity_u360;

            // Swaptions: underlying swap fixed leg conventions:
            // modified following, act/365

            // Physical settled swaption
            boost::shared_ptr<Swaption> swaption_p_a365 =
                vars.makeSwaption(swap_a365,exerciseDate,0.20);
            Real value_p_a365 = swaption_p_a365->NPV();
            // Cash settled swaption
            boost::shared_ptr<Swaption> swaption_c_a365 =
                vars.makeSwaption(swap_a365,exerciseDate,0.20,
                                  Settlement::Cash);
            Real value_c_a365 = swaption_c_a365->NPV();
            // the NPV's ratio must be equal to annuities ratio
            Real npv_ratio_a365 = value_c_a365 / value_p_a365;
            Real annuity_ratio_a365 =  cashannuity_a365 / annuity_a365;

            // Swaptions: underlying swap fixed leg conventions:
            // modified following, 30/360

            // Physical settled swaption
            boost::shared_ptr<Swaption> swaption_p_a360 =
                vars.makeSwaption(swap_a360,exerciseDate,0.20);
            Real value_p_a360 = swaption_p_a360->NPV();
            // Cash settled swaption
            boost::shared_ptr<Swaption> swaption_c_a360 =
                vars.makeSwaption(swap_a360,exerciseDate,0.20,
                                  Settlement::Cash);
            Real value_c_a360 = swaption_c_a360->NPV();
            // the NPV's ratio must be equal to annuities ratio
            Real npv_ratio_a360 = value_c_a360 / value_p_a360;
            Real annuity_ratio_a360 =  cashannuity_a360 / annuity_a360;

            // Swaptions: underlying swap fixed leg conventions:
            // unadjusted, act/365

            // Physical settled swaption
            boost::shared_ptr<Swaption> swaption_p_u365 =
                vars.makeSwaption(swap_u365,exerciseDate,0.20);
            Real value_p_u365 = swaption_p_u365->NPV();
            // Cash settled swaption
            boost::shared_ptr<Swaption> swaption_c_u365 =
                vars.makeSwaption(swap_u365,exerciseDate,0.20,
                                  Settlement::Cash);
            Real value_c_u365 = swaption_c_u365->NPV();
            // the NPV's ratio must be equal to annuities ratio
            Real npv_ratio_u365 = value_c_u365 / value_p_u365;
            Real annuity_ratio_u365 =  cashannuity_u365 / annuity_u365;

            if (std::fabs(annuity_ratio_u360-npv_ratio_u360)>1e-10 ) {
                BOOST_ERROR("\n" <<
                            "    The npv's ratio must be equal to " <<
                            " annuities ratio" << "\n"
                            "    Swaption " <<
                            exercises[i].units() << "y x " << lengths[j].units() << "y" <<
                            " (underlying swap fixed leg Unadjusted, 30/360)" << "\n" <<
                            "    Today           : " <<
                            vars.today << "\n" <<
                            "    Settlement date : " <<
                            vars.settlement << "\n" <<
                            "    Exercise date   : " <<
                            exerciseDate << "\n"   <<
                            "    Swap start date : " <<
                            startDate << "\n"   <<
                            "    Swap end date   : " <<
                            maturity <<     "\n"   <<
                            "    physical delivered swaption npv : " <<
                            value_p_u360 << "\t\t\t" <<
                            "    annuity : " <<
                            annuity_u360 << "\n" <<
                            "    cash delivered swaption npv :     " <<
                            value_c_u360 << "\t\t\t" <<
                            "    annuity : " <<
                            cashannuity_u360 << "\n" <<
                            "    npv ratio : " <<
                            npv_ratio_u360 << "\n" <<
                            "    annuity ratio : " <<
                            annuity_ratio_u360 << "\n" <<
                            "    difference : " <<
                            (annuity_ratio_u360-npv_ratio_u360) );
            }
            if (std::fabs(annuity_ratio_a365-npv_ratio_a365)>1e-10) {
                BOOST_ERROR("\n" <<
                            "    The npv's ratio must be equal to " <<
                            " annuities ratio" << "\n"
                            "    Swaption " <<
                            exercises[i].units() << "y x " << lengths[j].units() << "y" <<
                            " (underlying swap fixed leg Modified Following, act/365" << "\n" <<
                            "    Today           : " <<
                            vars.today << "\n" <<
                            "    Settlement date : " <<
                            vars.settlement << "\n" <<
                            "    Exercise date   : " <<
                            exerciseDate <<  "\n"  <<
                            "    Swap start date : " <<
                            startDate << "\n"   <<
                            "    Swap end date   : " <<
                            maturity <<     "\n"   <<
                            "    physical delivered swaption npv : "  <<
                            value_p_a365 << "\t\t\t" <<
                            "    annuity : " <<
                            annuity_a365 << "\n" <<
                            "    cash delivered swaption npv :     "  <<
                            value_c_a365 << "\t\t\t" <<
                            "    annuity : " <<
                            cashannuity_a365 << "\n" <<
                            "    npv ratio : " <<
                            npv_ratio_a365 << "\n" <<
                            "    annuity ratio : " <<
                            annuity_ratio_a365 << "\n" <<
                            "    difference : " <<
                            (annuity_ratio_a365-npv_ratio_a365) );
                }
            if (std::fabs(annuity_ratio_a360-npv_ratio_a360)>1e-10) {
                BOOST_ERROR("\n" <<
                            "    The npv's ratio must be equal to " <<
                            " annuities ratio" << "\n"
                            "    Swaption " <<
                            exercises[i].units() << "y x " << lengths[j].units() << "y" <<
                            " (underlying swap fixed leg Unadjusted, 30/360)" << "\n" <<
                            "    Today           : " <<
                            vars.today << "\n" <<
                            "    Settlement date : " <<
                            vars.settlement << "\n" <<
                            "    Exercise date   : " <<
                            exerciseDate << "\n"   <<
                            "    Swap start date : " <<
                            startDate << "\n"   <<
                            "    Swap end date   : " <<
                            maturity <<     "\n"   <<
                            "    physical delivered swaption npv : " <<
                            value_p_a360 << "\t\t\t" <<
                            "    annuity : " <<
                            annuity_a360 << "\n" <<
                            "    cash delivered swaption npv :     " <<
                            value_c_a360 << "\t\t\t" <<
                            "    annuity : " <<
                            cashannuity_a360 << "\n" <<
                            "    npv ratio : " <<
                            npv_ratio_a360 << "\n" <<
                            "    annuity ratio : " <<
                            annuity_ratio_a360 << "\n" <<
                            "    difference : " <<
                            (annuity_ratio_a360-npv_ratio_a360) );
            }
            if (std::fabs(annuity_ratio_u365-npv_ratio_u365)>1e-10) {
                BOOST_ERROR("\n" <<
                            "    The npv's ratio must be equal to " <<
                            " annuities ratio" << "\n"
                            "    Swaption " <<
                            exercises[i].units() << "y x " << lengths[j].units() << "y" <<
                            " (underlying swap fixed leg Unadjusted, act/365)" << "\n" <<
                            "    Today           : " <<
                            vars.today << "\n" <<
                            "    Settlement date : " <<
                            vars.settlement << "\n" <<
                            "    Exercise date   : " <<
                            exerciseDate << "\n"   <<
                            "    Swap start date : " <<
                            startDate << "\n"   <<
                            "    Swap end date   : " <<
                            maturity <<     "\n"   <<
                            "    physical delivered swaption npv : " <<
                            value_p_u365 << "\t\t\t" <<
                            "    annuity : " <<
                            annuity_u365 << "\n" <<
                            "    cash delivered swaption npv :     " <<
                            value_c_u365 << "\t\t\t" <<
                            "    annuity : " <<
                            cashannuity_u365 << "\n" <<
                            "    npv ratio : " <<
                            npv_ratio_u365 << "\n" <<
                            "    annuity ratio : " <<
                            annuity_ratio_u365 << "\n" <<
                            "    difference : " <<
                            (annuity_ratio_u365-npv_ratio_u365) );
            }
        }
    }
}
Example #19
0
void SwaptionTest::testVega() {

    BOOST_MESSAGE("Testing swaption vega...");

    CommonVars vars;

    Settlement::Type types[] = { Settlement::Physical, Settlement::Cash };
    Rate strikes[] = { 0.03, 0.04, 0.05, 0.06, 0.07 };
    Volatility vols[] = { 0.01, 0.20, 0.30, 0.70, 0.90 };
    Volatility shift = 1e-8;
    for (Size i=0; i<LENGTH(exercises); i++) {
        Date exerciseDate = vars.calendar.advance(vars.today, exercises[i]);
        Date startDate = vars.calendar.advance(exerciseDate,
                                           vars.settlementDays*Days);
        for (Size j=0; j<LENGTH(lengths); j++) {
            for (Size t=0; t<LENGTH(strikes); t++) {
                for (Size h=0; h<LENGTH(type); h++) {
                    boost::shared_ptr<VanillaSwap> swap =
                        MakeVanillaSwap(lengths[j], vars.index, strikes[t])
                                .withEffectiveDate(startDate)
                                .withFloatingLegSpread(0.0)
                                .withType(type[h]);
                    for (Size u=0; u<LENGTH(vols); u++) {
                        boost::shared_ptr<Swaption> swaption =
                            vars.makeSwaption(swap, exerciseDate,
                                              vols[u], types[h]);
                        // FLOATING_POINT_EXCEPTION
                        boost::shared_ptr<Swaption> swaption1 =
                            vars.makeSwaption(swap, exerciseDate,
                                              vols[u]-shift, types[h]);
                        boost::shared_ptr<Swaption> swaption2 =
                            vars.makeSwaption(swap, exerciseDate,
                                              vols[u]+shift, types[h]);

                        Real swaptionNPV = swaption->NPV();
                        Real numericalVegaPerPoint =
                            (swaption2->NPV()-swaption1->NPV())/(200.0*shift);
                        // check only relevant vega
                        if (numericalVegaPerPoint/swaptionNPV>1.0e-7) {
                            Real analyticalVegaPerPoint =
                                swaption->result<Real>("vega")/100.0;
                            Real discrepancy = std::fabs(analyticalVegaPerPoint
                                - numericalVegaPerPoint);
                            discrepancy /= numericalVegaPerPoint;
                            Real tolerance = 0.015;
                            if (discrepancy > tolerance)
                                BOOST_FAIL("failed to compute swaption vega:" <<
                                    "\n  option tenor:    " << exercises[i] <<
                                    "\n  volatility:      " << io::rate(vols[u]) <<
                                    "\n  option type:     " << swaption->type() <<
                                    "\n  swap tenor:      " << lengths[j] <<
                                    "\n  strike:          " << io::rate(strikes[t]) <<
                                    "\n  settlement:      " << types[h] <<
                                    "\n  nominal:         " << swaption->underlyingSwap()->nominal() <<
                                    "\n  npv:             " << swaptionNPV <<
                                    "\n  calculated vega: " << analyticalVegaPerPoint <<
                                    "\n  expected vega:   " << numericalVegaPerPoint <<
                                    "\n  discrepancy:     " << io::rate(discrepancy) <<
                                    "\n  tolerance:       " << io::rate(tolerance));
                        }
                    }
                }
            }
        }
    }
}
Example #20
0
void OvernightIndexedSwapTest::testBootstrap() {

    BOOST_TEST_MESSAGE("Testing Eonia-swap curve building...");

    CommonVars vars;

    std::vector<shared_ptr<RateHelper> > eoniaHelpers;
    std::vector<shared_ptr<RateHelper> > swap3mHelpers;

    shared_ptr<IborIndex> euribor3m(new Euribor3M);
    shared_ptr<Eonia> eonia(new Eonia);

    for (Size i = 0; i < LENGTH(depositData); i++) {
        Real rate = 0.01 * depositData[i].rate;
        shared_ptr<SimpleQuote> simple = shared_ptr<SimpleQuote>(new SimpleQuote(rate));
        shared_ptr<Quote> quote (simple);
        Period term = depositData[i].n * depositData[i].unit;
        shared_ptr<RateHelper> helper(new
                                      DepositRateHelper(Handle<Quote>(quote),
                                              term,
                                              depositData[i].settlementDays,
                                              euribor3m->fixingCalendar(),
                                              euribor3m->businessDayConvention(),
                                              euribor3m->endOfMonth(),
                                              euribor3m->dayCounter()));

        if (term <= 2*Days)
            eoniaHelpers.push_back(helper);
        if (term <= 3*Months)
            swap3mHelpers.push_back(helper);
    }

    for (Size i = 0; i < LENGTH(fraData); i++) {
        Real rate = 0.01 * fraData[i].rate;
        shared_ptr<SimpleQuote> simple = shared_ptr<SimpleQuote>(new SimpleQuote(rate));
        shared_ptr<Quote> quote (simple);
        shared_ptr<RateHelper> helper(new
                                      FraRateHelper(Handle<Quote>(quote),
                                              fraData[i].nExpiry,
                                              fraData[i].nMaturity,
                                              fraData[i].settlementDays,
                                              euribor3m->fixingCalendar(),
                                              euribor3m->businessDayConvention(),
                                              euribor3m->endOfMonth(),
                                              euribor3m->dayCounter()));
        swap3mHelpers.push_back(helper);
    }

    for (Size i = 0; i < LENGTH(eoniaSwapData); i++) {
        Real rate = 0.01 * eoniaSwapData[i].rate;
        shared_ptr<SimpleQuote> simple = shared_ptr<SimpleQuote>(new SimpleQuote(rate));
        shared_ptr<Quote> quote (simple);
        Period term = eoniaSwapData[i].n * eoniaSwapData[i].unit;
        shared_ptr<RateHelper> helper(new
                                      OISRateHelper(eoniaSwapData[i].settlementDays,
                                              term,
                                              Handle<Quote>(quote),
                                              eonia));
        eoniaHelpers.push_back(helper);
    }

    for (Size i = 0; i < LENGTH(swapData); i++) {
        Real rate = 0.01 * swapData[i].rate;
        shared_ptr<SimpleQuote> simple = shared_ptr<SimpleQuote>(new SimpleQuote(rate));
        shared_ptr<Quote> quote (simple);
        Period tenor = swapData[i].nIndexUnits * swapData[i].indexUnit;
        Period term = swapData[i].nTermUnits * swapData[i].termUnit;
        shared_ptr<RateHelper> helper(new SwapRateHelper(
                                          Handle<Quote>(quote),
                                          term,
                                          vars.calendar,
                                          vars.fixedSwapFrequency,
                                          vars.fixedSwapConvention,
                                          vars.fixedSwapDayCount,
                                          euribor3m));
        if (tenor == 3*Months)
            swap3mHelpers.push_back(helper);
    }

    shared_ptr<PiecewiseFlatForward> eoniaTS(new
            PiecewiseFlatForward (vars.today, eoniaHelpers, Actual365Fixed()));

    shared_ptr<PiecewiseFlatForward> swapTS(new
                                            PiecewiseFlatForward (vars.today, swap3mHelpers, Actual365Fixed()));

    vars.eoniaTermStructure.linkTo(eoniaTS);

    /*
    std::cout.setf (std::ios::fixed, std::ios::floatfield);
    std::cout.setf (std::ios::showpoint);
    */

    // test curve consistency
    Real tolerance = 1.0e-8;
    for (Size i = 0; i < LENGTH(eoniaSwapData); i++) {
        Rate expected = eoniaSwapData[i].rate;
        Period term = eoniaSwapData[i].n * eoniaSwapData[i].unit;
        shared_ptr<OvernightIndexedSwap> swap = vars.makeSwap(term, 0.0, 0.0);
        Rate calculated = 100.0 * swap->fairRate();
        Rate error = std::fabs(expected-calculated);

        if (error>tolerance)
            BOOST_FAIL("curve inconsistency:" << std::setprecision(10) <<
                       "\n swap length:     " << term <<
                       "\n quoted rate:     " << expected <<
                       "\n calculated rate: " << calculated <<
                       "\n error:           " << error <<
                       "\n tolerance:       " << tolerance);
    }

    // zero spread
    /*
    std::cout << "zero spread:" << std::endl;
    std::cout << "years date zero3m/% zero1d/% spread/bp" << std::endl;
    DayCounter dc = Actual365Fixed();
    for (Size i = 1; i <= 10; i++) {
        Date d = vars.today + i*Years;
        Rate zero1d = eoniaTS->zeroRate(d, dc, Continuous, Annual,false).rate();
        Rate zero3m = swapTS->zeroRate(d, dc, Continuous, Annual,false).rate();
        std::cout << std::setw(2) << i << "y  " << io::iso_date(d) << "  "
                  << std::setprecision(3)
                  << zero3m * 100.0 << " "
                  << zero1d * 100.0 << " "
                  << std::setprecision(1)
                  << (zero3m - zero1d) * 10000.0 << std::endl;
    }
    */
}
void SwaptionVolatilityMatrixTest::testSwaptionVolMatrixObservability() {

    BOOST_TEST_MESSAGE("Testing swaption volatility matrix observability...");

    CommonVars vars;

    boost::shared_ptr<SwaptionVolatilityMatrix> vol;
    std::string description;

    //floating reference date, floating market data
    description = "floating reference date, floating market data";
    vol = boost::shared_ptr<SwaptionVolatilityMatrix>(new
        SwaptionVolatilityMatrix(vars.conventions.calendar,
                                 vars.conventions.optionBdc,
                                 vars.atm.tenors.options,
                                 vars.atm.tenors.swaps,
                                 vars.atm.volsHandle,
                                 vars.conventions.dayCounter));
    vars.makeObservabilityTest(description, vol, true, true);

    //fixed reference date, floating market data
    description = "fixed reference date, floating market data";
    vol = boost::shared_ptr<SwaptionVolatilityMatrix>(new
        SwaptionVolatilityMatrix(Settings::instance().evaluationDate(),
                                 vars.conventions.calendar,
                                 vars.conventions.optionBdc,
                                 vars.atm.tenors.options,
                                 vars.atm.tenors.swaps,
                                 vars.atm.volsHandle,
                                 vars.conventions.dayCounter));
    vars.makeObservabilityTest(description, vol, true, false);

    // floating reference date, fixed market data
    description = "floating reference date, fixed market data";
    vol = boost::shared_ptr<SwaptionVolatilityMatrix>(new
        SwaptionVolatilityMatrix(vars.conventions.calendar,
                                 vars.conventions.optionBdc,
                                 vars.atm.tenors.options,
                                 vars.atm.tenors.swaps,
                                 vars.atm.volsHandle,
                                 vars.conventions.dayCounter));
    vars.makeObservabilityTest(description, vol, false, true);

    // fixed reference date, fixed market data
    description = "fixed reference date, fixed market data";
    vol = boost::shared_ptr<SwaptionVolatilityMatrix>(new
        SwaptionVolatilityMatrix(Settings::instance().evaluationDate(),
                                 vars.conventions.calendar,
                                 vars.conventions.optionBdc,
                                 vars.atm.tenors.options,
                                 vars.atm.tenors.swaps,
                                 vars.atm.volsHandle,
                                 vars.conventions.dayCounter));
    vars.makeObservabilityTest(description, vol, false, false);

   // fixed reference date and fixed market data, option dates
        //SwaptionVolatilityMatrix(const Date& referenceDate,
        //                         const std::vector<Date>& exerciseDates,
        //                         const std::vector<Period>& swapTenors,
        //                         const Matrix& volatilities,
        //                         const DayCounter& dayCounter);
}
Example #22
0
void BermudanSwaptionTest::testCachedValues() {

    BOOST_MESSAGE("Testing Bermudan swaption against cached values...");

    CommonVars vars;

    vars.today = Date(15, February, 2002);

    Settings::instance().evaluationDate() = vars.today;

    vars.settlement = Date(19, February, 2002);
    // flat yield term structure impling 1x5 swap at 5%
    vars.termStructure.linkTo(flatRate(vars.settlement,
                                          0.04875825,
                                          Actual365Fixed()));

    Rate atmRate = vars.makeSwap(0.0)->fairRate();

    boost::shared_ptr<VanillaSwap> itmSwap = vars.makeSwap(0.8*atmRate);
    boost::shared_ptr<VanillaSwap> atmSwap = vars.makeSwap(atmRate);
    boost::shared_ptr<VanillaSwap> otmSwap = vars.makeSwap(1.2*atmRate);

    Real a = 0.048696, sigma = 0.0058904;
    boost::shared_ptr<ShortRateModel> model(new HullWhite(vars.termStructure,
                                                          a, sigma));
    std::vector<Date> exerciseDates;
    const Leg& leg = atmSwap->fixedLeg();
    for (Size i=0; i<leg.size(); i++) {
        boost::shared_ptr<Coupon> coupon =
            boost::dynamic_pointer_cast<Coupon>(leg[i]);
        exerciseDates.push_back(coupon->accrualStartDate());
    }
    boost::shared_ptr<Exercise> exercise(new BermudanExercise(exerciseDates));

    boost::shared_ptr<PricingEngine> engine(new TreeSwaptionEngine(model, 50));

    #if defined(QL_USE_INDEXED_COUPON)
    Real itmValue = 42.2413, atmValue = 12.8789, otmValue = 2.4759;
    #else
    Real itmValue = 42.2470, atmValue = 12.8826, otmValue = 2.4769;
    #endif

    Real tolerance = 1.0e-4;

    Swaption swaption(itmSwap, exercise);
    swaption.setPricingEngine(engine);
    if (std::fabs(swaption.NPV()-itmValue) > tolerance)
        BOOST_ERROR("failed to reproduce cached in-the-money swaption value:\n"
                    << "calculated: " << swaption.NPV() << "\n"
                    << "expected:   " << itmValue);
    swaption = Swaption(atmSwap, exercise);
    swaption.setPricingEngine(engine);
    if (std::fabs(swaption.NPV()-atmValue) > tolerance)
        BOOST_ERROR("failed to reproduce cached at-the-money swaption value:\n"
                    << "calculated: " << swaption.NPV() << "\n"
                    << "expected:   " << atmValue);
    swaption = Swaption(otmSwap, exercise);
    swaption.setPricingEngine(engine);
    if (std::fabs(swaption.NPV()-otmValue) > tolerance)
        BOOST_ERROR("failed to reproduce cached out-of-the-money "
                    << "swaption value:\n"
                    << "calculated: " << swaption.NPV() << "\n"
                    << "expected:   " << otmValue);

    for (Size j=0; j<exerciseDates.size(); j++)
        exerciseDates[j] = vars.calendar.adjust(exerciseDates[j]-10);
    exercise =
        boost::shared_ptr<Exercise>(new BermudanExercise(exerciseDates));

    #if defined(QL_USE_INDEXED_COUPON)
    itmValue = 42.1917; atmValue = 12.7788; otmValue = 2.4388;
    #else
    itmValue = 42.1974; atmValue = 12.7825; otmValue = 2.4399;
    #endif

    swaption = Swaption(itmSwap, exercise);
    swaption.setPricingEngine(engine);
    if (std::fabs(swaption.NPV()-itmValue) > tolerance)
        BOOST_ERROR("failed to reproduce cached in-the-money swaption value:\n"
                    << "calculated: " << swaption.NPV() << "\n"
                    << "expected:   " << itmValue);
    swaption = Swaption(atmSwap, exercise);
    swaption.setPricingEngine(engine);
    if (std::fabs(swaption.NPV()-atmValue) > tolerance)
        BOOST_ERROR("failed to reproduce cached at-the-money swaption value:\n"
                    << "calculated: " << swaption.NPV() << "\n"
                    << "expected:   " << atmValue);
    swaption = Swaption(otmSwap, exercise);
    swaption.setPricingEngine(engine);
    if (std::fabs(swaption.NPV()-otmValue) > tolerance)
        BOOST_ERROR("failed to reproduce cached out-of-the-money "
                    << "swaption value:\n"
                    << "calculated: " << swaption.NPV() << "\n"
                    << "expected:   " << otmValue);
}
Example #23
0
void SwaptionTest::testImpliedVolatility() {

    BOOST_MESSAGE("Testing implied volatility for swaptions...");

    CommonVars vars;

    Size maxEvaluations = 100;
    Real tolerance = 1.0e-08;

    Settlement::Type types[] = { Settlement::Physical, Settlement::Cash };
    // test data
    Rate strikes[] = { 0.02, 0.03, 0.04, 0.05, 0.06, 0.07 };
    Volatility vols[] = { 0.01, 0.05, 0.10, 0.20, 0.30, 0.70, 0.90 };

    for (Size i=0; i<LENGTH(exercises); i++) {
        for (Size j=0; j<LENGTH(lengths); j++) {
            Date exerciseDate = vars.calendar.advance(vars.today,exercises[i]);
            Date startDate = vars.calendar.advance(exerciseDate,
                                                   vars.settlementDays, Days);
            for (Size t=0; t<LENGTH(strikes); t++) {
                for (Size k=0; k<LENGTH(type); k++) {
                    boost::shared_ptr<VanillaSwap> swap =
                        MakeVanillaSwap(lengths[j], vars.index, strikes[t])
                                .withEffectiveDate(startDate)
                                .withFloatingLegSpread(0.0)
                                .withType(type[k]);
                    for (Size h=0; h<LENGTH(types); h++) {
                        for (Size u=0; u<LENGTH(vols); u++) {
                            boost::shared_ptr<Swaption> swaption =
                                vars.makeSwaption(swap, exerciseDate,
                                                  vols[u], types[h]);
                            // Black price
                            Real value = swaption->NPV();
                            Volatility implVol = 0.0;
                            try {
                                implVol =
                                  swaption->impliedVolatility(value,
                                                              vars.termStructure,
                                                              0.10,
                                                              tolerance,
                                                              maxEvaluations);
                            } catch (std::exception& e) {
                                // couldn't bracket?
                                swaption->setPricingEngine(vars.makeEngine(0.0));
                                Real value2 = swaption->NPV();
                                if (std::fabs(value-value2) < tolerance) {
                                    // ok, just skip:
                                    continue;
                                }
                                // otherwise, report error
                                BOOST_ERROR("implied vol failure: " <<
                                            exercises[i] << "x" << lengths[j] << " " << type[k] <<
                                            "\nsettlement: " << types[h] <<
                                            "\nstrike      " << strikes[t] <<
                                            "\natm level:  " << io::rate(swap->fairRate()) <<
                                            "\nvol:        " << io::volatility(vols[u]) <<
                                            "\nprice:      " << value <<
                                            "\n" << e.what());
                            }
                            if (std::fabs(implVol-vols[u]) > tolerance) {
                                // the difference might not matter
                                swaption->setPricingEngine(vars.makeEngine(implVol));
                                Real value2 = swaption->NPV();
                                if (std::fabs(value-value2) > tolerance) {
                                    BOOST_ERROR("implied vol failure: " <<
                                        exercises[i] << "x" << lengths[j] << " " << type[k] <<
                                        "\nsettlement:    " << types[h] <<
                                        "\nstrike         " << strikes[t] <<
                                        "\natm level:     " << io::rate(swap->fairRate()) <<
                                        "\nvol:           " << io::volatility(vols[u]) <<
                                        "\nprice:         " << value <<
                                        "\nimplied vol:   " << io::volatility(implVol) <<
                                        "\nimplied price: " << value2);
                                }
                             }
                        }
                    }
                }
            }
        }
    }
}
Example #24
0
void OptionletStripperTest::testTermVolatilityStripping2() {

  BOOST_TEST_MESSAGE(
        "Testing forward/forward vol stripping from non-flat term vol "
        "surface using OptionletStripper2 class...");

  CommonVars vars;
  Settings::instance().evaluationDate() = Date::todaysDate();

  vars.setCapFloorTermVolCurve();
  vars.setCapFloorTermVolSurface();

  shared_ptr<IborIndex> iborIndex(new Euribor6M(vars.yieldTermStructure));

  // optionletstripper1
  boost::shared_ptr<OptionletStripper1> optionletStripper1(new
        OptionletStripper1(vars.capFloorVolSurface,
                           iborIndex,
                           Null<Rate>(),
                           vars.accuracy));

  boost::shared_ptr<StrippedOptionletAdapter> strippedOptionletAdapter1 =
        boost::shared_ptr<StrippedOptionletAdapter>(new
            StrippedOptionletAdapter(optionletStripper1));

  Handle<OptionletVolatilityStructure> vol1(strippedOptionletAdapter1);
  vol1->enableExtrapolation();

  // optionletstripper2
  boost::shared_ptr<OptionletStripper> optionletStripper2(new
                OptionletStripper2(optionletStripper1,
                                   vars.capFloorVolCurve));

  boost::shared_ptr<StrippedOptionletAdapter> strippedOptionletAdapter2(new
        StrippedOptionletAdapter(optionletStripper2));

  Handle<OptionletVolatilityStructure> vol2(strippedOptionletAdapter2);
  vol2->enableExtrapolation();

  // consistency check: diff(stripped vol1-stripped vol2)
  for (Size strikeIndex=0; strikeIndex<vars.strikes.size(); ++strikeIndex) {
    for (Size tenorIndex=0; tenorIndex<vars.optionTenors.size(); ++tenorIndex) {

      Volatility strippedVol1 = vol1->volatility(vars.optionTenors[tenorIndex],
                                                 vars.strikes[strikeIndex], true);

      Volatility strippedVol2 = vol2->volatility(vars.optionTenors[tenorIndex],
                                                 vars.strikes[strikeIndex], true);

      // vol from flat vol surface (for comparison only)
      Volatility flatVol = vars.capFloorVolSurface->volatility(vars.optionTenors[tenorIndex],
                                                               vars.strikes[strikeIndex], true);

      Real error = std::fabs(strippedVol1-strippedVol2);
      if (error>vars.tolerance)
      BOOST_FAIL("\noption tenor:  " << vars.optionTenors[tenorIndex] <<
                 "\nstrike:        " << io::rate(vars.strikes[strikeIndex]) <<
                 "\nstripped vol1: " << io::rate(strippedVol1) <<
                 "\nstripped vol2: " << io::rate(strippedVol2) <<
                 "\nflat vol:      " << io::rate(flatVol) <<
                 "\nerror:         " << io::rate(error) <<
                 "\ntolerance:     " << io::rate(vars.tolerance));
    }
  }
}
Example #25
0
void CapFloorTest::testStrikeDependency() {

    BOOST_TEST_MESSAGE("Testing cap/floor dependency on strike...");

    CommonVars vars;

    Integer lengths[] = { 1, 2, 3, 5, 7, 10, 15, 20 };
    Volatility vols[] = { 0.01, 0.05, 0.10, 0.15, 0.20 };
    Rate strikes[] = { 0.03, 0.04, 0.05, 0.06, 0.07 };

    Date startDate = vars.termStructure->referenceDate();

    for (Size i=0; i<LENGTH(lengths); i++) {
        for (Size j=0; j<LENGTH(vols); j++) {
            // store the results for different strikes...
            std::vector<Real> cap_values, floor_values;
            for (Size k=0; k<LENGTH(strikes); k++) {
                Leg leg = vars.makeLeg(startDate,lengths[i]);
                boost::shared_ptr<Instrument> cap =
                    vars.makeCapFloor(CapFloor::Cap,leg,
                                      strikes[k],vols[j]);
                cap_values.push_back(cap->NPV());
                boost::shared_ptr<Instrument> floor =
                    vars.makeCapFloor(CapFloor::Floor,leg,
                                      strikes[k],vols[j]);
                floor_values.push_back(floor->NPV());
            }
            // and check that they go the right way
            std::vector<Real>::iterator it =
                std::adjacent_find(cap_values.begin(),cap_values.end(),
                                   std::less<Real>());
            if (it != cap_values.end()) {
                Size n = it - cap_values.begin();
                BOOST_FAIL(
                    "NPV is increasing with the strike in a cap: \n"
                    << std::setprecision(2)
                    << "    length:     " << lengths[i] << " years\n"
                    << "    volatility: " << io::volatility(vols[j]) << "\n"
                    << "    value:      " << cap_values[n]
                    << " at strike: " << io::rate(strikes[n]) << "\n"
                    << "    value:      " << cap_values[n+1]
                    << " at strike: " << io::rate(strikes[n+1]));
            }
            // same for floors
            it = std::adjacent_find(floor_values.begin(),floor_values.end(),
                                    std::greater<Real>());
            if (it != floor_values.end()) {
                Size n = it - floor_values.begin();
                BOOST_FAIL(
                    "NPV is decreasing with the strike in a floor: \n"
                    << std::setprecision(2)
                    << "    length:     " << lengths[i] << " years\n"
                    << "    volatility: " << io::volatility(vols[j]) << "\n"
                    << "    value:      " << floor_values[n]
                    << " at strike: " << io::rate(strikes[n]) << "\n"
                    << "    value:      " << floor_values[n+1]
                    << " at strike: " << io::rate(strikes[n+1]));
            }
        }
    }
}
Example #26
0
void OptionletStripperTest::testTermVolatilityStrippingShiftedLogNormalVol() {

    BOOST_TEST_MESSAGE(
        "Testing forward/forward vol stripping from non-flat normal vol term "
        "vol surface for normal vol setup using OptionletStripper1 class...");

    CommonVars vars;
    Real shift = 0.03;
    Settings::instance().evaluationDate() = Date(30, April, 2015);

    vars.setRealCapFloorTermVolSurface();

    shared_ptr< IborIndex > iborIndex(new Euribor6M(vars.forwardingYTS));

    boost::shared_ptr< OptionletStripper > optionletStripper1(
        new OptionletStripper1(vars.capFloorVolRealSurface, iborIndex,
                               Null< Rate >(), vars.accuracy, 100,
                               vars.discountingYTS, ShiftedLognormal, shift,
                               true));

    boost::shared_ptr< StrippedOptionletAdapter > strippedOptionletAdapter =
        boost::shared_ptr< StrippedOptionletAdapter >(
            new StrippedOptionletAdapter(optionletStripper1));

    Handle< OptionletVolatilityStructure > vol(strippedOptionletAdapter);

    vol->enableExtrapolation();

    boost::shared_ptr< BlackCapFloorEngine > strippedVolEngine(
        new BlackCapFloorEngine(vars.discountingYTS, vol));

    boost::shared_ptr< CapFloor > cap;
    for (Size strikeIndex = 0; strikeIndex < vars.strikes.size();
         ++strikeIndex) {
        for (Size tenorIndex = 0; tenorIndex < vars.optionTenors.size();
             ++tenorIndex) {
            cap = MakeCapFloor(CapFloor::Cap, vars.optionTenors[tenorIndex],
                               iborIndex, vars.strikes[strikeIndex],
                               0 * Days).withPricingEngine(strippedVolEngine);

            Real priceFromStrippedVolatility = cap->NPV();

            boost::shared_ptr< PricingEngine >
                blackCapFloorEngineConstantVolatility(new BlackCapFloorEngine(
                    vars.discountingYTS, vars.termV[tenorIndex][strikeIndex],
                    vars.capFloorVolRealSurface->dayCounter(), shift));

            cap->setPricingEngine(blackCapFloorEngineConstantVolatility);
            Real priceFromConstantVolatility = cap->NPV();

            Real error = std::fabs(priceFromStrippedVolatility -
                                   priceFromConstantVolatility);
            if (error > vars.tolerance)
                BOOST_FAIL(
                    "\noption tenor:       "
                    << vars.optionTenors[tenorIndex] << "\nstrike:             "
                    << io::rate(vars.strikes[strikeIndex])
                    << "\nstripped vol price: "
                    << io::rate(priceFromStrippedVolatility)
                    << "\nconstant vol price: "
                    << io::rate(priceFromConstantVolatility)
                    << "\nerror:              " << io::rate(error)
                    << "\ntolerance:          " << io::rate(vars.tolerance));
        }
    }
}
Example #27
0
void CapFloorTest::testConsistency() {

    BOOST_TEST_MESSAGE("Testing consistency between cap, floor and collar...");

    CommonVars vars;

    Integer lengths[] = { 1, 2, 3, 5, 7, 10, 15, 20 };
    Rate cap_rates[] = { 0.03, 0.04, 0.05, 0.06, 0.07 };
    Rate floor_rates[] = { 0.03, 0.04, 0.05, 0.06, 0.07 };
    Volatility vols[] = { 0.01, 0.05, 0.10, 0.15, 0.20 };

    Date startDate = vars.termStructure->referenceDate();

    for (Size i=0; i<LENGTH(lengths); i++) {
      for (Size j=0; j<LENGTH(cap_rates); j++) {
        for (Size k=0; k<LENGTH(floor_rates); k++) {
          for (Size l=0; l<LENGTH(vols); l++) {

              Leg leg = vars.makeLeg(startDate,lengths[i]);
              boost::shared_ptr<CapFloor> cap =
                  vars.makeCapFloor(CapFloor::Cap,leg,
                                    cap_rates[j],vols[l]);
              boost::shared_ptr<CapFloor> floor =
                  vars.makeCapFloor(CapFloor::Floor,leg,
                                    floor_rates[k],vols[l]);
              Collar collar(leg,std::vector<Rate>(1,cap_rates[j]),
                            std::vector<Rate>(1,floor_rates[k]));
              collar.setPricingEngine(vars.makeEngine(vols[l]));

              if (std::fabs((cap->NPV()-floor->NPV())-collar.NPV()) > 1e-10) {
                  BOOST_FAIL(
                    "inconsistency between cap, floor and collar:\n"
                    << "    length:       " << lengths[i] << " years\n"
                    << "    volatility:   " << io::volatility(vols[l]) << "\n"
                    << "    cap value:    " << cap->NPV()
                    << " at strike: " << io::rate(cap_rates[j]) << "\n"
                    << "    floor value:  " << floor->NPV()
                    << " at strike: " << io::rate(floor_rates[k]) << "\n"
                    << "    collar value: " << collar.NPV());


              // test re-composition by optionlets, N.B. two per year
              Real capletsNPV = 0.0;
              std::vector<boost::shared_ptr<CapFloor> > caplets;
              for (Integer m=0; m<lengths[i]*2; m++) {
                caplets.push_back(cap->optionlet(m));
                caplets[m]->setPricingEngine(vars.makeEngine(vols[l]));
                capletsNPV += caplets[m]->NPV();
              }

              if (std::fabs(cap->NPV() - capletsNPV) > 1e-10) {
                BOOST_FAIL(
                  "sum of caplet NPVs does not equal cap NPV:\n"
                    << "    length:       " << lengths[i] << " years\n"
                    << "    volatility:   " << io::volatility(vols[l]) << "\n"
                    << "    cap value:    " << cap->NPV()
                    << " at strike: " << io::rate(cap_rates[j]) << "\n"
                    << "    sum of caplets value:  " << capletsNPV
                    << " at strike (first): " << io::rate(caplets[0]->capRates()[0]) << "\n"
                );
              }

              Real floorletsNPV = 0.0;
              std::vector<boost::shared_ptr<CapFloor> > floorlets;
              for (Integer m=0; m<lengths[i]*2; m++) {
                floorlets.push_back(floor->optionlet(m));
                floorlets[m]->setPricingEngine(vars.makeEngine(vols[l]));
                floorletsNPV += floorlets[m]->NPV();
              }

              if (std::fabs(floor->NPV() - floorletsNPV) > 1e-10) {
                BOOST_FAIL(
                  "sum of floorlet NPVs does not equal floor NPV:\n"
                    << "    length:       " << lengths[i] << " years\n"
                    << "    volatility:   " << io::volatility(vols[l]) << "\n"
                    << "    cap value:    " << floor->NPV()
                    << " at strike: " << io::rate(floor_rates[j]) << "\n"
                    << "    sum of floorlets value:  " << floorletsNPV
                    << " at strike (first): " << io::rate(floorlets[0]->floorRates()[0]) << "\n"
                );
              }

              Real collarletsNPV = 0.0;
              std::vector<boost::shared_ptr<CapFloor> > collarlets;
              for (Integer m=0; m<lengths[i]*2; m++) {
                collarlets.push_back(collar.optionlet(m));
                collarlets[m]->setPricingEngine(vars.makeEngine(vols[l]));
                collarletsNPV += collarlets[m]->NPV();
              }

              if (std::fabs(collar.NPV() - collarletsNPV) > 1e-10) {
                BOOST_FAIL(
                  "sum of collarlet NPVs does not equal floor NPV:\n"
                    << "    length:       " << lengths[i] << " years\n"
                    << "    volatility:   " << io::volatility(vols[l]) << "\n"
                    << "    cap value:    " << collar.NPV()
                    << " at strike floor: " << io::rate(floor_rates[j])
                    << " at strike cap: " << io::rate(cap_rates[j]) << "\n"
                    << "    sum of collarlets value:  " << collarletsNPV
                    << " at strike floor (first): " << io::rate(collarlets[0]->floorRates()[0])
                    << " at strike cap (first): " << io::rate(collarlets[0]->capRates()[0]) << "\n"
                );
              }




              }
          }
        }
      }
    }
}
void InflationCapFlooredCouponTest::testInstrumentEquality() {

    BOOST_MESSAGE("Testing inflation capped/floored coupon against inflation capfloor instrument...");

    CommonVars vars;

    Integer lengths[] = { 1, 2, 3, 5, 7, 10, 15, 20 };
    // vol is low ...
    Rate strikes[] = { 0.01, 0.025, 0.029, 0.03, 0.031, 0.035, 0.07 };
    // yoy inflation vol is generally very low
    Volatility vols[] = { 0.001, 0.005, 0.010, 0.015, 0.020 };

    // this is model independent
    // capped coupon = fwd - cap, and fwd = swap(0)
    // floored coupon = fwd + floor
    for (Size whichPricer = 0; whichPricer < 3; whichPricer++) {
        for (Size i=0; i<LENGTH(lengths); i++) {
            for (Size j=0; j<LENGTH(strikes); j++) {
                for (Size k=0; k<LENGTH(vols); k++) {

                    Leg leg = vars.makeYoYLeg(vars.evaluationDate,lengths[i]);

                    boost::shared_ptr<Instrument> cap
                    = vars.makeYoYCapFloor(YoYInflationCapFloor::Cap,
                                           leg, strikes[j], vols[k], whichPricer);

                    boost::shared_ptr<Instrument> floor
                    = vars.makeYoYCapFloor(YoYInflationCapFloor::Floor,
                                           leg, strikes[j], vols[k], whichPricer);

                    Date from = vars.nominalTS->referenceDate();
                    Date to = from+lengths[i]*Years;
                    Schedule yoySchedule = MakeSchedule().from(from).to(to)
                    .withTenor(1*Years)
                    .withCalendar(UnitedKingdom())
                    .withConvention(Unadjusted)
                    .backwards()
                    ;

                    YearOnYearInflationSwap swap(YearOnYearInflationSwap::Payer,
                                                    1000000.0,
                                                    yoySchedule,//fixed schedule, but same as yoy
                                                    0.0,//strikes[j],
                                                    vars.dc,
                                                    yoySchedule,
                                                    vars.iir,
                                                    vars.observationLag,
                                                    0.0,        //spread on index
                                                    vars.dc,
                                                    UnitedKingdom());

                    Handle<YieldTermStructure> hTS(vars.nominalTS);
                    boost::shared_ptr<PricingEngine> sppe(new DiscountingSwapEngine(hTS));
                    swap.setPricingEngine(sppe);

                    Leg leg2 = vars.makeYoYCapFlooredLeg(whichPricer, from,
                                                         lengths[i],
                                                         std::vector<Rate>(lengths[i],strikes[j]),//cap
                                                         std::vector<Rate>(),//floor
                                                         vols[k],
                                                         1.0,   // gearing
                                                         0.0);// spread

                    Leg leg3 = vars.makeYoYCapFlooredLeg(whichPricer, from,
                                                         lengths[i],
                                                         std::vector<Rate>(),// cap
                                                         std::vector<Rate>(lengths[i],strikes[j]),//floor
                                                         vols[k],
                                                         1.0,   // gearing
                                                         0.0);// spread

                    // N.B. nominals are 10e6
                    Real capped = CashFlows::npv(leg2,(**vars.nominalTS),false);
                    if ( fabs(capped - (swap.NPV() - cap->NPV())) > 1.0e-6) {
                        BOOST_FAIL(
                                   "capped coupon != swap(0) - cap:\n"
                                   << "    length:      " << lengths[i] << " years\n"
                                   << "    volatility:  " << io::volatility(vols[k]) << "\n"
                                   << "    strike:      " << io::rate(strikes[j]) << "\n"
                                   << "    cap value:   " << cap->NPV() << "\n"
                                   << "    swap value:  " << swap.NPV() << "\n"
                                   << "   capped coupon " << capped);
                    }


                    // N.B. nominals are 10e6
                    Real floored = CashFlows::npv(leg3,(**vars.nominalTS),false);
                    if ( fabs(floored - (swap.NPV() + floor->NPV())) > 1.0e-6) {
                        BOOST_FAIL(
                                   "floored coupon != swap(0) + floor :\n"
                                   << "    length:      " << lengths[i] << " years\n"
                                   << "    volatility:  " << io::volatility(vols[k]) << "\n"
                                   << "    strike:      " << io::rate(strikes[j]) << "\n"
                                   << "    floor value: " << floor->NPV() << "\n"
                                   << "    swap value:  " << swap.NPV() << "\n"
                                   << "  floored coupon " << floored);
                    }

                }
            }
        }
    }
}
void InflationCapFlooredCouponTest::testDecomposition() {

    BOOST_MESSAGE("Testing collared coupon against its decomposition...");

    CommonVars vars;

    Real tolerance = 1e-10;
    Real npvVanilla,npvCappedLeg,npvFlooredLeg,npvCollaredLeg,npvCap,npvFloor,npvCollar;
    Real error;
    Rate floorstrike = 0.05;
    Rate capstrike = 0.10;
    std::vector<Rate> caps(vars.length,capstrike);
    std::vector<Rate> caps0 = std::vector<Rate>();
    std::vector<Rate> floors(vars.length,floorstrike);
    std::vector<Rate> floors0 = std::vector<Rate>();
    Rate gearing_p = Rate(0.5);
    Spread spread_p = Spread(0.002);
    Rate gearing_n = Rate(-1.5);
    Spread spread_n = Spread(0.12);
    // fixed leg with zero rate
    Leg fixedLeg  =
    vars.makeFixedLeg(vars.startDate,vars.length);
    // floating leg with gearing=1 and spread=0
    Leg floatLeg  =
    vars.makeYoYLeg(vars.startDate,vars.length);
    // floating leg with positive gearing (gearing_p) and spread<>0
    Leg floatLeg_p =
    vars.makeYoYLeg(vars.startDate,vars.length,gearing_p,spread_p);
    // floating leg with negative gearing (gearing_n) and spread<>0
    Leg floatLeg_n =
    vars.makeYoYLeg(vars.startDate,vars.length,gearing_n,spread_n);
    // Swap with null fixed leg and floating leg with gearing=1 and spread=0
    Swap vanillaLeg(fixedLeg,floatLeg);
    // Swap with null fixed leg and floating leg with positive gearing and spread<>0
    Swap vanillaLeg_p(fixedLeg,floatLeg_p);
    // Swap with null fixed leg and floating leg with negative gearing and spread<>0
    Swap vanillaLeg_n(fixedLeg,floatLeg_n);

    boost::shared_ptr<PricingEngine> engine(
            new DiscountingSwapEngine(vars.nominalTS));

    vanillaLeg.setPricingEngine(engine);    // here use the autoset feature
    vanillaLeg_p.setPricingEngine(engine);
    vanillaLeg_n.setPricingEngine(engine);

    // CAPPED coupon - Decomposition of payoff
    // Payoff = Nom * Min(rate,strike) * accrualperiod =
    // = Nom * [rate + Min(0,strike-rate)] * accrualperiod =
    // = Nom * rate * accrualperiod - Nom * Max(rate-strike,0) * accrualperiod =
    // = VanillaFloatingLeg - Call
    //

    Size whichPricer = 0;

    // Case gearing = 1 and spread = 0
    Leg cappedLeg =
    vars.makeYoYCapFlooredLeg(whichPricer,vars.startDate,vars.length,
                           caps,floors0,vars.volatility);
    Swap capLeg(fixedLeg,cappedLeg);
    capLeg.setPricingEngine(engine);
    YoYInflationCap cap(floatLeg, std::vector<Rate>(1, capstrike));
    cap.setPricingEngine(vars.makeEngine(vars.volatility,whichPricer));
    npvVanilla = vanillaLeg.NPV();
    npvCappedLeg = capLeg.NPV();
    npvCap = cap.NPV();
    error = std::abs(npvCappedLeg - (npvVanilla-npvCap));
    if (error>tolerance) {
        BOOST_ERROR("\nYoY Capped Leg: gearing=1, spread=0%, strike=" << capstrike*100 <<
                    "%\n" <<
                    "  Capped Floating Leg NPV: " << npvCappedLeg << "\n" <<
                    "  Floating Leg NPV - Cap NPV: " << npvVanilla - npvCap << "\n" <<
                    "  Diff: " << error );
    }

    // gearing = 1 and spread = 0
    // FLOORED coupon - Decomposition of payoff
    // Payoff = Nom * Max(rate,strike) * accrualperiod =
    // = Nom * [rate + Max(0,strike-rate)] * accrualperiod =
    // = Nom * rate * accrualperiod + Nom * Max(strike-rate,0) * accrualperiod =
    // = VanillaFloatingLeg + Put
    //

    Leg flooredLeg =
    vars.makeYoYCapFlooredLeg(whichPricer,vars.startDate,vars.length,
                           caps0,floors,vars.volatility);
    Swap floorLeg(fixedLeg,flooredLeg);
    floorLeg.setPricingEngine(engine);
    YoYInflationFloor floor(floatLeg, std::vector<Rate>(1, floorstrike));
    floor.setPricingEngine(vars.makeEngine(vars.volatility,whichPricer));
    npvFlooredLeg = floorLeg.NPV();
    npvFloor = floor.NPV();
    error = std::abs(npvFlooredLeg-(npvVanilla + npvFloor));
    if (error>tolerance) {
        BOOST_ERROR("YoY Floored Leg: gearing=1, spread=0%, strike=" << floorstrike *100 <<
                    "%\n" <<
                    "  Floored Floating Leg NPV: " << npvFlooredLeg << "\n" <<
                    "  Floating Leg NPV + Floor NPV: " << npvVanilla + npvFloor << "\n" <<
                    "  Diff: " << error );
    }

    // gearing = 1 and spread = 0
    // COLLARED coupon - Decomposition of payoff
    // Payoff = Nom * Min(strikem,Max(rate,strikeM)) * accrualperiod =
    // = VanillaFloatingLeg - Collar
    //

    Leg collaredLeg =
    vars.makeYoYCapFlooredLeg(whichPricer,vars.startDate,vars.length,
                           caps,floors,vars.volatility);
    Swap collarLeg(fixedLeg,collaredLeg);
    collarLeg.setPricingEngine(engine);
    YoYInflationCollar collar(floatLeg,
                  std::vector<Rate>(1, capstrike),
                  std::vector<Rate>(1, floorstrike));
    collar.setPricingEngine(vars.makeEngine(vars.volatility,whichPricer));
    npvCollaredLeg = collarLeg.NPV();
    npvCollar = collar.NPV();
    error = std::abs(npvCollaredLeg -(npvVanilla - npvCollar));
    if (error>tolerance) {
        BOOST_ERROR("\nYoY Collared Leg: gearing=1, spread=0%, strike=" <<
                    floorstrike*100 << "% and " << capstrike*100 << "%\n" <<
                    "  Collared Floating Leg NPV: " << npvCollaredLeg << "\n" <<
                    "  Floating Leg NPV - Collar NPV: " << npvVanilla - npvCollar << "\n" <<
                    "  Diff: " << error );
    }

    // gearing = a and spread = b
    // CAPPED coupon - Decomposition of payoff
    // Payoff
    // = Nom * Min(a*rate+b,strike) * accrualperiod =
    // = Nom * [a*rate+b + Min(0,strike-a*rate-b)] * accrualperiod =
    // = Nom * a*rate+b * accrualperiod + Nom * Min(strike-b-a*rate,0) * accrualperiod
    // --> If a>0 (assuming positive effective strike):
    // Payoff = VanillaFloatingLeg - Call(a*rate+b,strike)
    // --> If a<0 (assuming positive effective strike):
    // Payoff = VanillaFloatingLeg + Nom * Min(strike-b+|a|*rate+,0) * accrualperiod =
    // = VanillaFloatingLeg + Put(|a|*rate+b,strike)
    //

    // Positive gearing
    Leg cappedLeg_p =
    vars.makeYoYCapFlooredLeg(whichPricer,vars.startDate,vars.length,caps,floors0,
                           vars.volatility,gearing_p,spread_p);
    Swap capLeg_p(fixedLeg,cappedLeg_p);
    capLeg_p.setPricingEngine(engine);
    YoYInflationCap cap_p(floatLeg_p,std::vector<Rate>(1,capstrike));
    cap_p.setPricingEngine(vars.makeEngine(vars.volatility,whichPricer));
    npvVanilla = vanillaLeg_p.NPV();
    npvCappedLeg = capLeg_p.NPV();
    npvCap = cap_p.NPV();
    error = std::abs(npvCappedLeg - (npvVanilla-npvCap));
    if (error>tolerance) {
        BOOST_ERROR("\nYoY Capped Leg: gearing=" << gearing_p << ", " <<
                    "spread= " << spread_p *100 <<
                    "%, strike=" << capstrike*100  << "%, " <<
                    "effective strike= " << (capstrike-spread_p)/gearing_p*100 <<
                    "%\n" <<
                    "  Capped Floating Leg NPV: " << npvCappedLeg << "\n" <<
                    "  Vanilla Leg NPV: " << npvVanilla << "\n" <<
                    "  Cap NPV: " << npvCap << "\n" <<
                    "  Floating Leg NPV - Cap NPV: " << npvVanilla - npvCap << "\n" <<
                    "  Diff: " << error );
    }

    // Negative gearing
    Leg cappedLeg_n =
    vars.makeYoYCapFlooredLeg(whichPricer,vars.startDate,vars.length,caps,floors0,
                           vars.volatility,gearing_n,spread_n);
    Swap capLeg_n(fixedLeg,cappedLeg_n);
    capLeg_n.setPricingEngine(engine);
    YoYInflationFloor floor_n(floatLeg,std::vector<Rate>(1,(capstrike-spread_n)/gearing_n));
    floor_n.setPricingEngine(vars.makeEngine(vars.volatility,whichPricer));
    npvVanilla = vanillaLeg_n.NPV();
    npvCappedLeg = capLeg_n.NPV();
    npvFloor = floor_n.NPV();
    error = std::abs(npvCappedLeg - (npvVanilla+ gearing_n*npvFloor));
    if (error>tolerance) {
        BOOST_ERROR("\nYoY Capped Leg: gearing=" << gearing_n << ", " <<
                    "spread= " << spread_n *100 <<
                    "%, strike=" << capstrike*100  << "%, " <<
                    "effective strike= " << (capstrike-spread_n)/gearing_n*100 <<
                    "%\n" <<
                    "  Capped Floating Leg NPV: " << npvCappedLeg << "\n" <<
                    "  npv Vanilla: " << npvVanilla << "\n" <<
                    "  npvFloor: " << npvFloor << "\n" <<
                    "  Floating Leg NPV - Cap NPV: " << npvVanilla + gearing_n*npvFloor << "\n" <<
                    "  Diff: " << error );
    }

    // gearing = a and spread = b
    // FLOORED coupon - Decomposition of payoff
    // Payoff
    // = Nom * Max(a*rate+b,strike) * accrualperiod =
    // = Nom * [a*rate+b + Max(0,strike-a*rate-b)] * accrualperiod =
    // = Nom * a*rate+b * accrualperiod + Nom * Max(strike-b-a*rate,0) * accrualperiod
    // --> If a>0 (assuming positive effective strike):
    // Payoff = VanillaFloatingLeg + Put(a*rate+b,strike)
    // --> If a<0 (assuming positive effective strike):
    // Payoff = VanillaFloatingLeg + Nom * Max(strike-b+|a|*rate+,0) * accrualperiod =
    // = VanillaFloatingLeg - Call(|a|*rate+b,strike)
    //

    // Positive gearing
    Leg flooredLeg_p1 =
    vars.makeYoYCapFlooredLeg(whichPricer,vars.startDate,vars.length,caps0,floors,
                           vars.volatility,gearing_p,spread_p);
    Swap floorLeg_p1(fixedLeg,flooredLeg_p1);
    floorLeg_p1.setPricingEngine(engine);
    YoYInflationFloor floor_p1(floatLeg_p,std::vector<Rate>(1,floorstrike));
    floor_p1.setPricingEngine(vars.makeEngine(vars.volatility,whichPricer));
    npvVanilla = vanillaLeg_p.NPV();
    npvFlooredLeg = floorLeg_p1.NPV();
    npvFloor = floor_p1.NPV();
    error = std::abs(npvFlooredLeg - (npvVanilla+npvFloor));
    if (error>tolerance) {
        BOOST_ERROR("\nYoY Floored Leg: gearing=" << gearing_p << ", "
                    << "spread= " << spread_p *100<< "%, strike=" << floorstrike *100 << "%, "
                    << "effective strike= " << (floorstrike-spread_p)/gearing_p*100
                    << "%\n" <<
                    "  Floored Floating Leg NPV: "    << npvFlooredLeg
                    << "\n" <<
                    "  Floating Leg NPV + Floor NPV: " << npvVanilla + npvFloor
                    << "\n" <<
                    "  Diff: " << error );
    }
    // Negative gearing
    Leg flooredLeg_n =
    vars.makeYoYCapFlooredLeg(whichPricer,vars.startDate,vars.length,caps0,floors,
                           vars.volatility,gearing_n,spread_n);
    Swap floorLeg_n(fixedLeg,flooredLeg_n);
    floorLeg_n.setPricingEngine(engine);
    YoYInflationCap cap_n(floatLeg,std::vector<Rate>(1,(floorstrike-spread_n)/gearing_n));
    cap_n.setPricingEngine(vars.makeEngine(vars.volatility,whichPricer));
    npvVanilla = vanillaLeg_n.NPV();
    npvFlooredLeg = floorLeg_n.NPV();
    npvCap = cap_n.NPV();
    error = std::abs(npvFlooredLeg - (npvVanilla - gearing_n*npvCap));
    if (error>tolerance) {
        BOOST_ERROR("\nYoY Capped Leg: gearing=" << gearing_n << ", " <<
                    "spread= " << spread_n *100 <<
                    "%, strike=" << floorstrike*100  << "%, " <<
                    "effective strike= " << (floorstrike-spread_n)/gearing_n*100 <<
                    "%\n" <<
                    "  Capped Floating Leg NPV: " << npvFlooredLeg << "\n" <<
                    "  Floating Leg NPV - Cap NPV: " << npvVanilla - gearing_n*npvCap << "\n" <<
                    "  Diff: " << error );
    }
    // gearing = a and spread = b
    // COLLARED coupon - Decomposition of payoff
    // Payoff = Nom * Min(caprate,Max(a*rate+b,floorrate)) * accrualperiod
    // --> If a>0 (assuming positive effective strike):
    // Payoff = VanillaFloatingLeg - Collar(a*rate+b, floorrate, caprate)
    // --> If a<0 (assuming positive effective strike):
    // Payoff = VanillaFloatingLeg + Collar(|a|*rate+b, caprate, floorrate)
    //
    // Positive gearing
    Leg collaredLeg_p =
    vars.makeYoYCapFlooredLeg(whichPricer,vars.startDate,vars.length,caps,floors,
                           vars.volatility,gearing_p,spread_p);
    Swap collarLeg_p1(fixedLeg,collaredLeg_p);
    collarLeg_p1.setPricingEngine(engine);
    YoYInflationCollar collar_p(floatLeg_p,
                    std::vector<Rate>(1,capstrike),
                    std::vector<Rate>(1,floorstrike));
    collar_p.setPricingEngine(vars.makeEngine(vars.volatility,whichPricer));
    npvVanilla = vanillaLeg_p.NPV();
    npvCollaredLeg = collarLeg_p1.NPV();
    npvCollar = collar_p.NPV();
    error = std::abs(npvCollaredLeg - (npvVanilla - npvCollar));
    if (error>tolerance) {
        BOOST_ERROR("\nYoY Collared Leg: gearing=" << gearing_p << ", "
                    << "spread= " << spread_p*100 << "%, strike="
                    << floorstrike*100 << "% and " << capstrike*100
                    << "%, "
                    << "effective strike=" << (floorstrike-spread_p)/gearing_p*100
                    <<  "% and " << (capstrike-spread_p)/gearing_p*100
                    << "%\n" <<
                    "  Collared Floating Leg NPV: "    << npvCollaredLeg
                    << "\n" <<
                    "  Floating Leg NPV - Collar NPV: " << npvVanilla - npvCollar
                    << "\n" <<
                    "  Diff: " << error );
    }
    // Negative gearing
    Leg collaredLeg_n =
    vars.makeYoYCapFlooredLeg(whichPricer,vars.startDate,vars.length,caps,floors,
                           vars.volatility,gearing_n,spread_n);
    Swap collarLeg_n1(fixedLeg,collaredLeg_n);
    collarLeg_n1.setPricingEngine(engine);
    YoYInflationCollar collar_n(floatLeg,
                    std::vector<Rate>(1,(floorstrike-spread_n)/gearing_n),
                    std::vector<Rate>(1,(capstrike-spread_n)/gearing_n));
    collar_n.setPricingEngine(vars.makeEngine(vars.volatility,whichPricer));
    npvVanilla = vanillaLeg_n.NPV();
    npvCollaredLeg = collarLeg_n1.NPV();
    npvCollar = collar_n.NPV();
    error = std::abs(npvCollaredLeg - (npvVanilla - gearing_n*npvCollar));
    if (error>tolerance) {
        BOOST_ERROR("\nYoY Collared Leg: gearing=" << gearing_n << ", "
                    << "spread= " << spread_n*100 << "%, strike="
                    << floorstrike*100 << "% and " << capstrike*100
                    << "%, "
                    << "effective strike=" << (floorstrike-spread_n)/gearing_n*100
                    <<  "% and " << (capstrike-spread_n)/gearing_n*100
                    << "%\n" <<
                    "  Collared Floating Leg NPV: "    << npvCollaredLeg
                    << "\n" <<
                    "  Floating Leg NPV - Collar NPV: " << npvVanilla - gearing_n*npvCollar
                    << "\n" <<
                    "  Diff: " << error );
    }
}
Example #30
0
void SwaptionTest::testSpreadTreatment() {

    BOOST_MESSAGE("Testing swaption treatment of spread...");

    CommonVars vars;

    Spread spreads[] = { -0.002, -0.001, 0.0, 0.001, 0.002 };

    for (Size i=0; i<LENGTH(exercises); i++) {
        for (Size j=0; j<LENGTH(lengths); j++) {
            for (Size k=0; k<LENGTH(type); k++) {
                Date exerciseDate = vars.calendar.advance(vars.today,
                                                          exercises[i]);
                Date startDate =
                    vars.calendar.advance(exerciseDate,
                                          vars.settlementDays,Days);
                for (Size l=0; l<LENGTH(spreads); l++) {
                    boost::shared_ptr<VanillaSwap> swap =
                        MakeVanillaSwap(lengths[j], vars.index, 0.06)
                                .withEffectiveDate(startDate)
                                .withFloatingLegSpread(spreads[l])
                                .withType(type[k]);
                    // FLOATING_POINT_EXCEPTION
                    Spread correction = spreads[l] *
                                        swap->floatingLegBPS() /
                                        swap->fixedLegBPS();
                    boost::shared_ptr<VanillaSwap> equivalentSwap =
                        MakeVanillaSwap(lengths[j], vars.index, 0.06+correction)
                                .withEffectiveDate(startDate)
                                .withFloatingLegSpread(0.0)
                                .withType(type[k]);
                    boost::shared_ptr<Swaption> swaption1 =
                        vars.makeSwaption(swap,exerciseDate,0.20);
                    boost::shared_ptr<Swaption> swaption2 =
                        vars.makeSwaption(equivalentSwap,exerciseDate,0.20);
                    boost::shared_ptr<Swaption> swaption1_cash =
                        vars.makeSwaption(swap,exerciseDate,0.20,
                                          Settlement::Cash);
                    boost::shared_ptr<Swaption> swaption2_cash =
                        vars.makeSwaption(equivalentSwap,exerciseDate,0.20,
                                          Settlement::Cash);
                    if (std::fabs(swaption1->NPV()-swaption2->NPV()) > 1.0e-6)
                        BOOST_ERROR("wrong spread treatment:" <<
                            "\nexercise: " << exerciseDate <<
                            "\nlength:   " << lengths[j] <<
                            "\ntype      " << type[k] <<
                            "\nspread:   " << io::rate(spreads[l]) <<
                            "\noriginal swaption value:   " << swaption1->NPV() <<
                            "\nequivalent swaption value: " << swaption2->NPV());

                    if (std::fabs(swaption1_cash->NPV()-swaption2_cash->NPV()) > 1.0e-6)
                        BOOST_ERROR("wrong spread treatment:" <<
                            "\nexercise date: " << exerciseDate <<
                            "\nlength: " << lengths[j] <<
                            "\npay " << (type[k] ? "fixed" : "floating") <<
                            "\nspread: " << io::rate(spreads[l]) <<
                            "\nvalue of original swaption:   "  << swaption1_cash->NPV() <<
                            "\nvalue of equivalent swaption: "  << swaption2_cash->NPV());
                }

            }
        }
    }
}