Example #1
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 #2
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 #3
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 #4
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);
}
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 #6
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 #7
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"
                );
              }




              }
          }
        }
      }
    }
}
Example #8
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]));
            }
        }
    }
}