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 collectNodeData(MarketModelEvolver& evolver, MarketModelMultiProduct& product, MarketModelNodeDataProvider& dataProvider, MarketModelExerciseValue& rebate, MarketModelExerciseValue& control, Size numberOfPaths, std::vector<std::vector<NodeData> >& collectedData) { std::vector<Real> numerairesHeld; QL_REQUIRE(product.numberOfProducts() == 1, "a single product is required"); // TODO: check that all objects have compatible evolutions // (same rate times; evolution times for product, basis // system, rebate and control must be subsets of the passed // evolution times; rebate, control and basis system must have // the same exercise---not evolution---times) std::vector<Size> numberCashFlowsThisStep(1); std::vector<std::vector<CashFlow> > cashFlowsGenerated(1); cashFlowsGenerated[0].resize( product.maxNumberOfCashFlowsPerProductPerStep()); std::vector<Time> rateTimes = product.evolution().rateTimes(); std::vector<Time> cashFlowTimes = product.possibleCashFlowTimes(); std::vector<Time> rebateTimes = rebate.possibleCashFlowTimes(); std::vector<Time> controlTimes = control.possibleCashFlowTimes(); Size i, n; n = cashFlowTimes.size(); std::vector<MarketModelDiscounter> productDiscounters; productDiscounters.reserve(n); for (i=0; i<n; ++i) productDiscounters.push_back( MarketModelDiscounter(cashFlowTimes[i], rateTimes)); n = rebateTimes.size(); std::vector<MarketModelDiscounter> rebateDiscounters; rebateDiscounters.reserve(n); for (i=0; i<n; ++i) rebateDiscounters.push_back( MarketModelDiscounter(rebateTimes[i], rateTimes)); n = controlTimes.size(); std::vector<MarketModelDiscounter> controlDiscounters; controlDiscounters.reserve(n); for (i=0; i<n; ++i) controlDiscounters.push_back( MarketModelDiscounter(controlTimes[i], rateTimes)); EvolutionDescription evolution = product.evolution(); const std::vector<Size>& numeraires = evolver.numeraires(); std::vector<Time> evolutionTimes = evolution.evolutionTimes(); std::valarray<bool> isProductTime = isInSubset(evolutionTimes, product.evolution().evolutionTimes()); std::valarray<bool> isRebateTime = isInSubset(evolutionTimes, rebate.evolution().evolutionTimes()); std::valarray<bool> isControlTime = isInSubset(evolutionTimes, control.evolution().evolutionTimes()); std::valarray<bool> isBasisTime = isInSubset(evolutionTimes, dataProvider.evolution().evolutionTimes()); std::valarray<bool> isExerciseTime(false,evolutionTimes.size()); std::valarray<bool> v = rebate.isExerciseTime(); Size exercises = 0; for (i=0; i<evolutionTimes.size(); ++i) { if (isRebateTime[i]) { isExerciseTime[i] = v[exercises]; ++exercises; } } collectedData.resize(exercises+1); for (i=0; i<collectedData.size(); ++i) collectedData[i].resize(numberOfPaths); for (i=0; i<numberOfPaths; ++i) { evolver.startNewPath(); product.reset(); rebate.reset(); control.reset(); dataProvider.reset(); Real principalInNumerairePortfolio = 1.0; bool done = false; Size nextExercise = 0; collectedData[0][i].cumulatedCashFlows = 0.0; do { Size currentStep = evolver.currentStep(); evolver.advanceStep(); const CurveState& currentState = evolver.currentState(); Size numeraire = numeraires[currentStep]; if (isRebateTime[currentStep]) rebate.nextStep(currentState); if (isControlTime[currentStep]) control.nextStep(currentState); if (isBasisTime[currentStep]) dataProvider.nextStep(currentState); if (isExerciseTime[currentStep]) { NodeData& data = collectedData[nextExercise+1][i]; CashFlow exerciseValue = rebate.value(currentState); data.exerciseValue = exerciseValue.amount * rebateDiscounters[exerciseValue.timeIndex] .numeraireBonds(currentState, numeraire) / principalInNumerairePortfolio; dataProvider.values(currentState, data.values); CashFlow controlValue = control.value(currentState); data.controlValue = controlValue.amount * controlDiscounters[controlValue.timeIndex] .numeraireBonds(currentState, numeraire) / principalInNumerairePortfolio; data.cumulatedCashFlows = 0.0; data.isValid = true; ++nextExercise; } if (isProductTime[currentStep]) { done = product.nextTimeStep(currentState, numberCashFlowsThisStep, cashFlowsGenerated); for (Size j=0; j<numberCashFlowsThisStep[0]; ++j) { const CashFlow& cf = cashFlowsGenerated[0][j]; collectedData[nextExercise][i].cumulatedCashFlows += cf.amount * productDiscounters[cf.timeIndex] .numeraireBonds(currentState, numeraire) / principalInNumerairePortfolio; } } if (!done) { Size nextNumeraire = numeraires[currentStep+1]; principalInNumerairePortfolio *= currentState.discountRatio(numeraire, nextNumeraire); } } while (!done); // fill the remaining (un)collected data with nulls for (Size j = nextExercise; j < exercises; ++j) { NodeData& data = collectedData[j+1][i]; data.exerciseValue = data.controlValue = 0.0; data.cumulatedCashFlows = 0.0; data.isValid = false; } } }
int InverseFloater(Real rateLevel) { Size numberRates =20; Real accrual = 0.5; Real firstTime = 0.5; Real strike =0.15; Real fixedMultiplier = 2.0; Real floatingSpread =0.0; bool payer = true; std::vector<Real> rateTimes(numberRates+1); for (Size i=0; i < rateTimes.size(); ++i) rateTimes[i] = firstTime + i*accrual; std::vector<Real> paymentTimes(numberRates); std::vector<Real> accruals(numberRates,accrual); std::vector<Real> fixedStrikes(numberRates,strike); std::vector<Real> floatingSpreads(numberRates,floatingSpread); std::vector<Real> fixedMultipliers(numberRates,fixedMultiplier); for (Size i=0; i < paymentTimes.size(); ++i) paymentTimes[i] = firstTime + (i+1)*accrual; MultiStepInverseFloater inverseFloater( rateTimes, accruals, accruals, fixedStrikes, fixedMultipliers, floatingSpreads, paymentTimes, payer); //exercise schedule, we can exercise on any rate time except the last one std::vector<Rate> exerciseTimes(rateTimes); exerciseTimes.pop_back(); // naive exercise strategy, exercise above a trigger level Real trigger =0.05; std::vector<Rate> swapTriggers(exerciseTimes.size(), trigger); SwapRateTrigger naifStrategy(rateTimes, swapTriggers, exerciseTimes); // Longstaff-Schwartz exercise strategy std::vector<std::vector<NodeData> > collectedData; std::vector<std::vector<Real> > basisCoefficients; // control that does nothing, need it because some control is expected NothingExerciseValue control(rateTimes); SwapForwardBasisSystem basisSystem(rateTimes,exerciseTimes); // SwapBasisSystem basisSystem(rateTimes,exerciseTimes); // rebate that does nothing, need it because some rebate is expected // when you break a swap nothing happens. NothingExerciseValue nullRebate(rateTimes); CallSpecifiedMultiProduct dummyProduct = CallSpecifiedMultiProduct(inverseFloater, naifStrategy, ExerciseAdapter(nullRebate)); EvolutionDescription evolution = dummyProduct.evolution(); // parameters for models Size seed = 12332; // for Sobol generator Size trainingPaths = 65536; Size paths = 65536; Size vegaPaths =16384; #ifdef _DEBUG trainingPaths = 8192; paths = 8192; vegaPaths = 1024; #endif std::cout << " inverse floater \n"; std::cout << " fixed strikes : " << strike << "\n"; std::cout << " number rates : " << numberRates << "\n"; std::cout << "training paths, " << trainingPaths << "\n"; std::cout << "paths, " << paths << "\n"; std::cout << "vega Paths, " << vegaPaths << "\n"; // set up a calibration, this would typically be done by using a calibrator //Real rateLevel =0.08; std::cout << " rate level " << rateLevel << "\n"; Real initialNumeraireValue = 0.95; Real volLevel = 0.11; Real beta = 0.2; Real gamma = 1.0; Size numberOfFactors = std::min<Size>(5,numberRates); Spread displacementLevel =0.02; // set up vectors std::vector<Rate> initialRates(numberRates,rateLevel); std::vector<Volatility> volatilities(numberRates, volLevel); std::vector<Spread> displacements(numberRates, displacementLevel); ExponentialForwardCorrelation correlations( rateTimes,volLevel, beta,gamma); FlatVol calibration( volatilities, boost::shared_ptr<PiecewiseConstantCorrelation>(new ExponentialForwardCorrelation(correlations)), evolution, numberOfFactors, initialRates, displacements); boost::shared_ptr<MarketModel> marketModel(new FlatVol(calibration)); // we use a factory since there is data that will only be known later SobolBrownianGeneratorFactory generatorFactory( SobolBrownianGenerator::Diagonal, seed); std::vector<Size> numeraires( moneyMarketMeasure(evolution)); // the evolver will actually evolve the rates LogNormalFwdRatePc evolver(marketModel, generatorFactory, numeraires // numeraires for each step ); boost::shared_ptr<MarketModelEvolver> evolverPtr(new LogNormalFwdRatePc(evolver)); int t1= clock(); // gather data before computing exercise strategy collectNodeData(evolver, inverseFloater, basisSystem, nullRebate, control, trainingPaths, collectedData); int t2 = clock(); // calculate the exercise strategy's coefficients genericLongstaffSchwartzRegression(collectedData, basisCoefficients); // turn the coefficients into an exercise strategy LongstaffSchwartzExerciseStrategy exerciseStrategy( basisSystem, basisCoefficients, evolution, numeraires, nullRebate, control); // callable receiver swap CallSpecifiedMultiProduct callableProduct = CallSpecifiedMultiProduct( inverseFloater, exerciseStrategy, ExerciseAdapter(nullRebate)); MultiProductComposite allProducts; allProducts.add(inverseFloater); allProducts.add(callableProduct); allProducts.finalize(); AccountingEngine accounter(evolverPtr, Clone<MarketModelMultiProduct>(allProducts), initialNumeraireValue); SequenceStatisticsInc stats; accounter.multiplePathValues (stats,paths); int t3 = clock(); std::vector<Real> means(stats.mean()); for (Size i=0; i < means.size(); ++i) std::cout << means[i] << "\n"; std::cout << " time to build strategy, " << (t2-t1)/static_cast<Real>(CLOCKS_PER_SEC)<< ", seconds.\n"; std::cout << " time to price, " << (t3-t2)/static_cast<Real>(CLOCKS_PER_SEC)<< ", seconds.\n"; // vegas // do it twice once with factorwise bumping, once without Size pathsToDoVegas = vegaPaths; for (Size i=0; i < 4; ++i) { bool allowFactorwiseBumping = i % 2 > 0 ; bool doCaps = i / 2 > 0 ; LogNormalFwdRateEuler evolverEuler(marketModel, generatorFactory, numeraires ) ; MarketModelPathwiseInverseFloater pathwiseInverseFloater( rateTimes, accruals, accruals, fixedStrikes, fixedMultipliers, floatingSpreads, paymentTimes, payer); Clone<MarketModelPathwiseMultiProduct> pathwiseInverseFloaterPtr(pathwiseInverseFloater.clone()); // callable inverse floater CallSpecifiedPathwiseMultiProduct callableProductPathwise(pathwiseInverseFloaterPtr, exerciseStrategy); Clone<MarketModelPathwiseMultiProduct> callableProductPathwisePtr(callableProductPathwise.clone()); std::vector<std::vector<Matrix> > theBumps(theVegaBumps(allowFactorwiseBumping, marketModel, doCaps)); PathwiseVegasOuterAccountingEngine accountingEngineVegas(boost::shared_ptr<LogNormalFwdRateEuler>(new LogNormalFwdRateEuler(evolverEuler)), // pathwiseInverseFloaterPtr, callableProductPathwisePtr, marketModel, theBumps, initialNumeraireValue); std::vector<Real> values,errors; accountingEngineVegas.multiplePathValues(values,errors,pathsToDoVegas); std::cout << "vega output \n"; std::cout << " factorwise bumping " << allowFactorwiseBumping << "\n"; std::cout << " doCaps " << doCaps << "\n"; Size r=0; std::cout << " price estimate, " << values[r++] << "\n"; for (Size i=0; i < numberRates; ++i, ++r) std::cout << " Delta, " << i << ", " << values[r] << ", " << errors[r] << "\n"; Real totalVega = 0.0; for (; r < values.size(); ++r) { std::cout << " vega, " << r - 1 - numberRates<< ", " << values[r] << " ," << errors[r] << "\n"; totalVega += values[r]; } std::cout << " total Vega, " << totalVega << "\n"; } bool doUpperBound = true; if (doUpperBound) { // upper bound MTBrownianGeneratorFactory uFactory(seed+142); boost::shared_ptr<MarketModelEvolver> upperEvolver(new LogNormalFwdRatePc( boost::shared_ptr<MarketModel>(new FlatVol(calibration)), uFactory, numeraires // numeraires for each step )); std::vector<boost::shared_ptr<MarketModelEvolver> > innerEvolvers; std::valarray<bool> isExerciseTime = isInSubset(evolution.evolutionTimes(), exerciseStrategy.exerciseTimes()); for (Size s=0; s < isExerciseTime.size(); ++s) { if (isExerciseTime[s]) { MTBrownianGeneratorFactory iFactory(seed+s); boost::shared_ptr<MarketModelEvolver> e =boost::shared_ptr<MarketModelEvolver> (static_cast<MarketModelEvolver*>(new LogNormalFwdRatePc(boost::shared_ptr<MarketModel>(new FlatVol(calibration)), uFactory, numeraires , // numeraires for each step s))); innerEvolvers.push_back(e); } } UpperBoundEngine uEngine(upperEvolver, // does outer paths innerEvolvers, // for sub-simulations that do continuation values inverseFloater, nullRebate, inverseFloater, nullRebate, exerciseStrategy, initialNumeraireValue); Statistics uStats; Size innerPaths = 255; Size outerPaths =256; int t4 = clock(); uEngine.multiplePathValues(uStats,outerPaths,innerPaths); Real upperBound = uStats.mean(); Real upperSE = uStats.errorEstimate(); int t5=clock(); std::cout << " Upper - lower is, " << upperBound << ", with standard error " << upperSE << "\n"; std::cout << " time to compute upper bound is, " << (t5-t4)/static_cast<Real>(CLOCKS_PER_SEC) << ", seconds.\n"; } return 0; }
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) {}