LongstaffSchwartzExerciseStrategy::LongstaffSchwartzExerciseStrategy( const Clone<MarketModelBasisSystem>& basisSystem, const std::vector<std::vector<Real> >& basisCoefficients, const EvolutionDescription& evolution, const std::vector<Size>& numeraires, const Clone<MarketModelExerciseValue>& exercise, const Clone<MarketModelExerciseValue>& control) : basisSystem_(basisSystem), basisCoefficients_(basisCoefficients), exercise_(exercise), control_(control), numeraires_(numeraires) { checkCompatibility(evolution, numeraires); relevantTimes_ = evolution.evolutionTimes(); isBasisTime_.resize(relevantTimes_.size()); isBasisTime_ = isInSubset(relevantTimes_, basisSystem_->evolution().evolutionTimes()); isRebateTime_.resize(relevantTimes_.size()); isRebateTime_ = isInSubset(relevantTimes_, exercise_->evolution().evolutionTimes()); isControlTime_.resize(relevantTimes_.size()); isControlTime_ = isInSubset(relevantTimes_, control_->evolution().evolutionTimes()); exerciseIndex_ = std::vector<Size>(relevantTimes_.size()); isExerciseTime_.resize(relevantTimes_.size(), false); std::valarray<bool> v = exercise_->isExerciseTime(); Size exercises = 0, idx = 0; Size i; for (i=0; i<relevantTimes_.size(); ++i) { exerciseIndex_[i] = exercises; if (isRebateTime_[i]) { isExerciseTime_[i] = v[idx++]; if (isExerciseTime_[i]) { exerciseTimes_.push_back(relevantTimes_[i]); ++exercises; } } } std::vector<Time> rateTimes = evolution.rateTimes(); std::vector<Time> rebateTimes = exercise_->possibleCashFlowTimes(); rebateDiscounters_.reserve(rebateTimes.size()); for (i=0; i<rebateTimes.size(); ++i) rebateDiscounters_.push_back( MarketModelDiscounter(rebateTimes[i], rateTimes)); std::vector<Time> controlTimes = control_->possibleCashFlowTimes(); controlDiscounters_.reserve(controlTimes.size()); for (i=0; i<controlTimes.size(); ++i) controlDiscounters_.push_back( MarketModelDiscounter(controlTimes[i], rateTimes)); std::vector<Size> basisSizes = basisSystem_->numberOfFunctions(); basisValues_.resize(basisSystem_->numberOfExercises()); for (i=0; i<basisValues_.size(); ++i) basisValues_[i].resize(basisSizes[i]); }
shared_ptr<MarketModel> FlatVolFactory::create(const EvolutionDescription& evolution, Size numberOfFactors) const { const vector<Time>& rateTimes = evolution.rateTimes(); Size numberOfRates = rateTimes.size()-1; vector<Rate> initialRates(numberOfRates); for (Size i=0; i<numberOfRates; ++i) initialRates[i] = yieldCurve_->forwardRate(rateTimes[i], rateTimes[i+1], Simple); vector<Volatility> displacedVolatilities(numberOfRates); for (Size i=0; i<numberOfRates; ++i) { Volatility vol = // to be changes volatility_(rateTimes[i]); displacedVolatilities[i] = initialRates[i]*vol/(initialRates[i]+displacement_); } vector<Spread> displacements(numberOfRates, displacement_); Matrix correlations = exponentialCorrelations(evolution.rateTimes(), longTermCorrelation_, beta_); shared_ptr<PiecewiseConstantCorrelation> corr(new TimeHomogeneousForwardCorrelation(correlations, rateTimes)); return shared_ptr<MarketModel>(new FlatVol(displacedVolatilities, corr, evolution, numberOfFactors, initialRates, displacements)); }
FlatVol::FlatVol( const vector<Volatility>& vols, const shared_ptr<PiecewiseConstantCorrelation>& corr, const EvolutionDescription& evolution, Size numberOfFactors, const vector<Rate>& initialRates, const vector<Spread>& displacements) : numberOfFactors_(numberOfFactors), numberOfRates_(initialRates.size()), numberOfSteps_(evolution.evolutionTimes().size()), initialRates_(initialRates), displacements_(displacements), evolution_(evolution), pseudoRoots_(numberOfSteps_, Matrix(numberOfRates_, numberOfFactors_)) { const vector<Time>& rateTimes = evolution.rateTimes(); QL_REQUIRE(numberOfRates_==rateTimes.size()-1, "mismatch between number of rates (" << numberOfRates_ << ") and rate times"); QL_REQUIRE(numberOfRates_==displacements.size(), "mismatch between number of rates (" << numberOfRates_ << ") and displacements (" << displacements.size() << ")"); QL_REQUIRE(numberOfRates_==vols.size(), "mismatch between number of rates (" << numberOfRates_ << ") and vols (" << vols.size() << ")"); QL_REQUIRE(numberOfRates_<=numberOfFactors_*numberOfSteps_, "number of rates (" << numberOfRates_ << ") greater than number of factors (" << numberOfFactors_ << ") times number of steps (" << numberOfSteps_ << ")"); QL_REQUIRE(numberOfFactors<=numberOfRates_, "number of factors (" << numberOfFactors << ") cannot be greater than numberOfRates (" << numberOfRates_ << ")"); QL_REQUIRE(numberOfFactors>0, "number of factors (" << numberOfFactors << ") must be greater than zero"); Time effStopTime = 0.0; const vector<Time>& corrTimes = corr->times(); const vector<Time>& evolTimes = evolution.evolutionTimes(); Matrix covariance(numberOfRates_, numberOfRates_); for (Size k=0, kk=0; k<numberOfSteps_; ++k) { // one covariance per evolution step std::fill(covariance.begin(), covariance.end(), 0.0); // there might be more than one correlation matrix // in a single evolution step for (; corrTimes[kk]<evolTimes[k]; ++kk) { Time effStartTime = effStopTime; effStopTime = corrTimes[kk]; const Matrix& corrMatrix = corr->correlation(kk); for (Size i=0; i<numberOfRates_; ++i) { for (Size j=i; j<numberOfRates_; ++j) { Real cov = flatVolCovariance(effStartTime, effStopTime, rateTimes[i], rateTimes[j], vols[i], vols[j]); covariance[i][j] += cov * corrMatrix[i][j]; } } } // last part in the evolution step Time effStartTime = effStopTime; effStopTime = evolTimes[k]; const Matrix& corrMatrix = corr->correlation(kk); for (Size i=0; i<numberOfRates_; ++i) { for (Size j=i; j<numberOfRates_; ++j) { Real cov = flatVolCovariance(effStartTime, effStopTime, rateTimes[i], rateTimes[j], vols[i], vols[j]); covariance[i][j] += cov * corrMatrix[i][j]; } } // no more use for the kk-th correlation matrix while (kk<corrTimes.size() && corrTimes[kk]<=evolTimes[k]) ++kk; // make it symmetric for (Size i=0; i<numberOfRates_; ++i) { for (Size j=i+1; j<numberOfRates_; ++j) { covariance[j][i] = covariance[i][j]; } } pseudoRoots_[k] = rankReducedSqrt(covariance, numberOfFactors, 1.0, SalvagingAlgorithm::None); QL_ENSURE(pseudoRoots_[k].rows()==numberOfRates_, "step " << k << " flat vol wrong number of rows: " << pseudoRoots_[k].rows() << " instead of " << numberOfRates_); QL_ENSURE(pseudoRoots_[k].columns()==numberOfFactors, "step " << k << " flat vol wrong number of columns: " << pseudoRoots_[k].columns() << " instead of " << numberOfFactors_); } }
void SwapForwardMappingsTest::testSwaptionImpliedVolatility() { BOOST_TEST_MESSAGE("Testing implied swaption vol in LMM using HW approximation..."); MarketModelData marketData; const std::vector<Time>& rateTimes = marketData.rateTimes(); const std::vector<Rate>& forwards = marketData.forwards(); const Size nbRates = marketData.nbRates(); LMMCurveState lmmCurveState(rateTimes); lmmCurveState.setOnForwardRates(forwards); const Real longTermCorr=0.5; const Real beta = .2; Real strike = .03; for (Size startIndex = 1; startIndex+2 < nbRates; startIndex = startIndex+5) { Size endIndex = nbRates-2; boost::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(Option::Call, strike)); MultiStepSwaption product(rateTimes, startIndex, endIndex,payoff ); const EvolutionDescription evolution = product.evolution(); const Size numberOfFactors = nbRates; Spread displacement = marketData.displacements().front(); Matrix jacobian = SwapForwardMappings::coterminalSwapZedMatrix( lmmCurveState, displacement); Matrix correlations = exponentialCorrelations(evolution.rateTimes(), longTermCorr, beta); boost::shared_ptr<PiecewiseConstantCorrelation> corr(new TimeHomogeneousForwardCorrelation(correlations, rateTimes)); boost::shared_ptr<MarketModel> lmmMarketModel(new FlatVol(marketData.volatilities(), corr, evolution, numberOfFactors, lmmCurveState.forwardRates(), marketData.displacements())); SobolBrownianGeneratorFactory generatorFactory(SobolBrownianGenerator::Diagonal); std::vector<Size> numeraires(nbRates, nbRates); boost::shared_ptr<MarketModelEvolver> evolver(new LogNormalFwdRatePc (lmmMarketModel, generatorFactory, numeraires)); boost::shared_ptr<SequenceStatisticsInc> stats = simulate(marketData.discountFactors(), evolver, product); std::vector<Real> results = stats->mean(); std::vector<Real> errors = stats->errorEstimate(); Real estimatedImpliedVol = SwapForwardMappings::swaptionImpliedVolatility(*lmmMarketModel,startIndex,endIndex); Real swapRate = lmmCurveState.cmSwapRate(startIndex,endIndex-startIndex); Real swapAnnuity = lmmCurveState.cmSwapAnnuity(startIndex,startIndex,endIndex-startIndex)*marketData.discountFactors()[startIndex]; boost::shared_ptr<PlainVanillaPayoff> payoffDis( new PlainVanillaPayoff(Option::Call, strike+displacement)); Real expectedSwaption = BlackCalculator(payoffDis, swapRate+displacement, estimatedImpliedVol *sqrt(rateTimes[startIndex]), swapAnnuity).value(); Real error = expectedSwaption - results[0]; Real errorInSds = error/errors[0]; if (fabs(errorInSds) > 3.5 ) BOOST_ERROR( "expected\t" << expectedSwaption << "\tLMM\t" << results[0] << "\tstdev:\t" << errors[0] << "\t" <<errorInSds); } }
void SwapForwardMappingsTest::testForwardCoterminalMappings() { BOOST_TEST_MESSAGE("Testing forward-rate coterminal-swap mappings..."); MarketModelData marketData; const std::vector<Time>& rateTimes = marketData.rateTimes(); const std::vector<Rate>& forwards = marketData.forwards(); const Size nbRates = marketData.nbRates(); LMMCurveState lmmCurveState(rateTimes); lmmCurveState.setOnForwardRates(forwards); const Real longTermCorr=0.5; const Real beta = .2; Real strike = .03; MultiStepCoterminalSwaptions product = makeMultiStepCoterminalSwaptions(rateTimes, strike); const EvolutionDescription evolution = product.evolution(); const Size numberOfFactors = nbRates; Spread displacement = marketData.displacements().front(); Matrix jacobian = SwapForwardMappings::coterminalSwapZedMatrix( lmmCurveState, displacement); Matrix correlations = exponentialCorrelations(evolution.rateTimes(), longTermCorr, beta); boost::shared_ptr<PiecewiseConstantCorrelation> corr(new TimeHomogeneousForwardCorrelation(correlations, rateTimes)); boost::shared_ptr<MarketModel> smmMarketModel(new FlatVol(marketData.volatilities(), corr, evolution, numberOfFactors, lmmCurveState.coterminalSwapRates(), marketData.displacements())); boost::shared_ptr<MarketModel> lmmMarketModel(new CotSwapToFwdAdapter(smmMarketModel)); SobolBrownianGeneratorFactory generatorFactory(SobolBrownianGenerator::Diagonal); std::vector<Size> numeraires(nbRates, nbRates); boost::shared_ptr<MarketModelEvolver> evolver(new LogNormalFwdRatePc (lmmMarketModel, generatorFactory, numeraires)); boost::shared_ptr<SequenceStatisticsInc> stats = simulate(marketData.discountFactors(), evolver, product); std::vector<Real> results = stats->mean(); std::vector<Real> errors = stats->errorEstimate(); const std::vector<DiscountFactor>& todaysDiscounts = marketData.discountFactors(); const std::vector<Rate>& todaysCoterminalSwapRates = lmmCurveState.coterminalSwapRates(); for (Size i=0; i<nbRates; ++i) { const Matrix& cotSwapsCovariance = smmMarketModel->totalCovariance(i); //Matrix cotSwapsCovariance= jacobian * forwardsCovariance * transpose(jacobian); //Time expiry = rateTimes[i]; boost::shared_ptr<PlainVanillaPayoff> payoff( new PlainVanillaPayoff(Option::Call, strike+displacement)); //const std::vector<Time>& taus = lmmCurveState.rateTaus(); Real expectedSwaption = BlackCalculator(payoff, todaysCoterminalSwapRates[i]+displacement, std::sqrt(cotSwapsCovariance[i][i]), lmmCurveState.coterminalSwapAnnuity(i,i) * todaysDiscounts[i]).value(); if (fabs(expectedSwaption-results[i]) > 0.0001) BOOST_ERROR( "expected\t" << expectedSwaption << "\tLMM\t" << results[i] << "\tstdev:\t" << errors[i] << "\t" <<std::fabs(results[i]- expectedSwaption)/errors[i]); } }
MultiStepNothing::MultiStepNothing(const EvolutionDescription& evolution, Size numberOfProducts, Size doneIndex) : MultiProductMultiStep(evolution.rateTimes()), numberOfProducts_(numberOfProducts), doneIndex_(doneIndex) {}