std::pair<std::vector<Rate>, std::vector<Volatility> > InterpolatedYoYOptionletStripper<Interpolator1D>::slice( const Date &d) const { const std::vector<Real>& Ks = strikes(); const Size nK = Ks.size(); std::pair<std::vector<Rate>, std::vector<Volatility> > result = std::make_pair(std::vector<Rate>(nK), std::vector<Volatility>(nK)); for (Size i = 0; i < nK; i++) { Rate K = Ks[i]; Volatility v = volCurves_[i]->volatility(d, K); result.first[i] = K; result.second[i] = v; } return result; }
std::vector<Real> SwaptionVolCube1::spreadVolInterpolation( const Date& atmOptionDate, const Period& atmSwapTenor) const { Time atmOptionTime = timeFromReference(atmOptionDate); Time atmTimeLength = swapLength(atmSwapTenor); std::vector<Real> result; const std::vector<Time>& optionTimes(sparseParameters_.optionTimes()); const std::vector<Time>& swapLengths(sparseParameters_.swapLengths()); const std::vector<Date>& optionDates = sparseParameters_.optionDates(); const std::vector<Period>& swapTenors = sparseParameters_.swapTenors(); std::vector<Real>::const_iterator optionTimesPreviousNode, swapLengthsPreviousNode; optionTimesPreviousNode = std::lower_bound(optionTimes.begin(), optionTimes.end(), atmOptionTime); Size optionTimesPreviousIndex = optionTimesPreviousNode - optionTimes.begin(); if (optionTimesPreviousIndex >0) optionTimesPreviousIndex --; swapLengthsPreviousNode = std::lower_bound(swapLengths.begin(), swapLengths.end(), atmTimeLength); Size swapLengthsPreviousIndex = swapLengthsPreviousNode - swapLengths.begin(); if (swapLengthsPreviousIndex >0) swapLengthsPreviousIndex --; std::vector< std::vector<boost::shared_ptr<SmileSection> > > smiles; std::vector<boost::shared_ptr<SmileSection> > smilesOnPreviousExpiry; std::vector<boost::shared_ptr<SmileSection> > smilesOnNextExpiry; QL_REQUIRE(optionTimesPreviousIndex+1 < sparseSmiles_.size(), "optionTimesPreviousIndex+1 >= sparseSmiles_.size()"); QL_REQUIRE(swapLengthsPreviousIndex+1 < sparseSmiles_[0].size(), "swapLengthsPreviousIndex+1 >= sparseSmiles_[0].size()"); smilesOnPreviousExpiry.push_back( sparseSmiles_[optionTimesPreviousIndex][swapLengthsPreviousIndex]); smilesOnPreviousExpiry.push_back( sparseSmiles_[optionTimesPreviousIndex][swapLengthsPreviousIndex+1]); smilesOnNextExpiry.push_back( sparseSmiles_[optionTimesPreviousIndex+1][swapLengthsPreviousIndex]); smilesOnNextExpiry.push_back( sparseSmiles_[optionTimesPreviousIndex+1][swapLengthsPreviousIndex+1]); smiles.push_back(smilesOnPreviousExpiry); smiles.push_back(smilesOnNextExpiry); std::vector<Real> optionsNodes(2); optionsNodes[0] = optionTimes[optionTimesPreviousIndex]; optionsNodes[1] = optionTimes[optionTimesPreviousIndex+1]; std::vector<Date> optionsDateNodes(2); optionsDateNodes[0] = optionDates[optionTimesPreviousIndex]; optionsDateNodes[1] = optionDates[optionTimesPreviousIndex+1]; std::vector<Real> swapLengthsNodes(2); swapLengthsNodes[0] = swapLengths[swapLengthsPreviousIndex]; swapLengthsNodes[1] = swapLengths[swapLengthsPreviousIndex+1]; std::vector<Period> swapTenorNodes(2); swapTenorNodes[0] = swapTenors[swapLengthsPreviousIndex]; swapTenorNodes[1] = swapTenors[swapLengthsPreviousIndex+1]; Rate atmForward = atmStrike(atmOptionDate, atmSwapTenor); Matrix atmForwards(2, 2, 0.0); Matrix atmVols(2, 2, 0.0); for (Size i=0; i<2; i++) { for (Size j=0; j<2; j++) { atmForwards[i][j] = atmStrike(optionsDateNodes[i], swapTenorNodes[j]); // atmVols[i][j] = smiles[i][j]->volatility(atmForwards[i][j]); atmVols[i][j] = atmVol_->volatility( optionsDateNodes[i], swapTenorNodes[j], atmForwards[i][j]); /* With the old implementation the interpolated spreads on ATM volatilities were null even if the spreads on ATM volatilities to be interpolated were non-zero. The new implementation removes this behaviour, but introduces a small ERROR in the cube: even if no spreads are applied on any cube ATM volatility corresponding to quoted smile sections (that is ATM volatilities in sparse cube), the cube ATM volatilities corresponding to not quoted smile sections (that is ATM volatilities in dense cube) are no more exactly the quoted values, but that ones PLUS the linear interpolation of the fit errors on the ATM volatilities in sparse cube whose spreads are used in the calculation. A similar imprecision is introduced to the volatilities in dense cube whith moneyness near to 1. (See below how spreadVols are calculated). The extent of this error depends on the quality of the fit: in case of good fits it is negligibile. */ } } for (Size k=0; k<nStrikes_; k++){ const Real strike = std::max(atmForward + strikeSpreads_[k],MINSTRIKE); const Real moneyness = atmForward/strike; Matrix strikes(2,2,0.); Matrix spreadVols(2,2,0.); for (Size i=0; i<2; i++){ for (Size j=0; j<2; j++){ strikes[i][j] = atmForwards[i][j]/moneyness; spreadVols[i][j] = smiles[i][j]->volatility(strikes[i][j]) - atmVols[i][j]; } } Cube localInterpolator(optionsDateNodes, swapTenorNodes, optionsNodes, swapLengthsNodes, 1); localInterpolator.setLayer(0, spreadVols); localInterpolator.updateInterpolators(); result.push_back(localInterpolator(atmOptionTime, atmTimeLength)[0]); } return result; }
void SwaptionVolCube1::sabrCalibrationSection( const Cube& marketVolCube, Cube& parametersCube, const Period& swapTenor) const { const std::vector<Time>& optionTimes = marketVolCube.optionTimes(); const std::vector<Time>& swapLengths = marketVolCube.swapLengths(); const std::vector<Date>& optionDates = marketVolCube.optionDates(); const std::vector<Period>& swapTenors = marketVolCube.swapTenors(); Size k = std::find(swapTenors.begin(), swapTenors.end(), swapTenor) - swapTenors.begin(); QL_REQUIRE(k != swapTenors.size(), "swap tenor not found"); std::vector<Real> calibrationResult(8,0.); const std::vector<Matrix>& tmpMarketVolCube = marketVolCube.points(); std::vector<Real> strikes(strikeSpreads_.size()); std::vector<Real> volatilities(strikeSpreads_.size()); for (Size j=0; j<optionTimes.size(); j++) { Rate atmForward = atmStrike(optionDates[j], swapTenors[k]); strikes.clear(); volatilities.clear(); for (Size i=0; i<nStrikes_; i++){ Real strike = atmForward+strikeSpreads_[i]; if(strike>=MINSTRIKE) { strikes.push_back(strike); volatilities.push_back(tmpMarketVolCube[i][j][k]); } } const std::vector<Real>& guess = parametersGuess_.operator()( optionTimes[j], swapLengths[k]); const boost::shared_ptr<SABRInterpolation> sabrInterpolation = boost::shared_ptr<SABRInterpolation>(new SABRInterpolation(strikes.begin(), strikes.end(), volatilities.begin(), optionTimes[j], atmForward, guess[0], guess[1], guess[2], guess[3], isParameterFixed_[0], isParameterFixed_[1], isParameterFixed_[2], isParameterFixed_[3], vegaWeightedSmileFit_, endCriteria_, optMethod_, errorAccept_, useMaxError_, maxGuesses_)); sabrInterpolation->update(); Real interpolationError = sabrInterpolation->rmsError(); calibrationResult[0]=sabrInterpolation->alpha(); calibrationResult[1]=sabrInterpolation->beta(); calibrationResult[2]=sabrInterpolation->nu(); calibrationResult[3]=sabrInterpolation->rho(); calibrationResult[4]=atmForward; calibrationResult[5]=interpolationError; calibrationResult[6]=sabrInterpolation->maxError(); calibrationResult[7]=sabrInterpolation->endCriteria(); QL_ENSURE(calibrationResult[7]!=EndCriteria::MaxIterations, "section calibration failed: " "option tenor " << optionDates[j] << ", swap tenor " << swapTenors[k] << ": max iteration (" << endCriteria_->maxIterations() << ")" << ", alpha " << calibrationResult[0]<< ", beta " << calibrationResult[1] << ", nu " << calibrationResult[2] << ", rho " << calibrationResult[3] << ", max error " << calibrationResult[6] << ", error " << calibrationResult[5] ); QL_ENSURE(useMaxError_ ? calibrationResult[6] : calibrationResult[5] < maxErrorTolerance_, "section calibration failed: " "option tenor " << optionDates[j] << ", swap tenor " << swapTenors[k] << (useMaxError_ ? ": max error " : ": error ") << (useMaxError_ ? calibrationResult[6] : calibrationResult[5]) << ", alpha " << calibrationResult[0] << ", beta " << calibrationResult[1] << ", nu " << calibrationResult[2] << ", rho " << calibrationResult[3] << (useMaxError_ ? ": error" : ": max error ") << (useMaxError_ ? calibrationResult[5] : calibrationResult[6]) ); parametersCube.setPoint(optionDates[j], swapTenors[k], optionTimes[j], swapLengths[k], calibrationResult); parametersCube.updateInterpolators(); } }
SwaptionVolCube1::Cube SwaptionVolCube1::sabrCalibration(const Cube& marketVolCube) const { const std::vector<Time>& optionTimes = marketVolCube.optionTimes(); const std::vector<Time>& swapLengths = marketVolCube.swapLengths(); const std::vector<Date>& optionDates = marketVolCube.optionDates(); const std::vector<Period>& swapTenors = marketVolCube.swapTenors(); Matrix alphas(optionTimes.size(), swapLengths.size(),0.); Matrix betas(alphas); Matrix nus(alphas); Matrix rhos(alphas); Matrix forwards(alphas); Matrix errors(alphas); Matrix maxErrors(alphas); Matrix endCriteria(alphas); const std::vector<Matrix>& tmpMarketVolCube = marketVolCube.points(); std::vector<Real> strikes(strikeSpreads_.size()); std::vector<Real> volatilities(strikeSpreads_.size()); for (Size j=0; j<optionTimes.size(); j++) { for (Size k=0; k<swapLengths.size(); k++) { Rate atmForward = atmStrike(optionDates[j], swapTenors[k]); strikes.clear(); volatilities.clear(); for (Size i=0; i<nStrikes_; i++){ Real strike = atmForward+strikeSpreads_[i]; if(strike>=MINSTRIKE) { strikes.push_back(strike); volatilities.push_back(tmpMarketVolCube[i][j][k]); } } const std::vector<Real>& guess = parametersGuess_.operator()( optionTimes[j], swapLengths[k]); const boost::shared_ptr<SABRInterpolation> sabrInterpolation = boost::shared_ptr<SABRInterpolation>(new SABRInterpolation(strikes.begin(), strikes.end(), volatilities.begin(), optionTimes[j], atmForward, guess[0], guess[1], guess[2], guess[3], isParameterFixed_[0], isParameterFixed_[1], isParameterFixed_[2], isParameterFixed_[3], vegaWeightedSmileFit_, endCriteria_, optMethod_, errorAccept_, useMaxError_, maxGuesses_)); sabrInterpolation->update(); Real rmsError = sabrInterpolation->rmsError(); Real maxError = sabrInterpolation->maxError(); alphas [j][k] = sabrInterpolation->alpha(); betas [j][k] = sabrInterpolation->beta(); nus [j][k] = sabrInterpolation->nu(); rhos [j][k] = sabrInterpolation->rho(); forwards [j][k] = atmForward; errors [j][k] = rmsError; maxErrors [j][k] = maxError; endCriteria[j][k] = sabrInterpolation->endCriteria(); QL_ENSURE(endCriteria[j][k]!=EndCriteria::MaxIterations, "global swaptions calibration failed: " "MaxIterations reached: " << "\n" << "option maturity = " << optionDates[j] << ", \n" << "swap tenor = " << swapTenors[k] << ", \n" << "error = " << io::rate(errors[j][k]) << ", \n" << "max error = " << io::rate(maxErrors[j][k]) << ", \n" << " alpha = " << alphas[j][k] << "n" << " beta = " << betas[j][k] << "\n" << " nu = " << nus[j][k] << "\n" << " rho = " << rhos[j][k] << "\n" ); QL_ENSURE(useMaxError_ ? maxError : rmsError < maxErrorTolerance_, "global swaptions calibration failed: " "option tenor " << optionDates[j] << ", swap tenor " << swapTenors[k] << (useMaxError_ ? ": max error " : ": error") << (useMaxError_ ? maxError : rmsError) << " alpha = " << alphas[j][k] << "n" << " beta = " << betas[j][k] << "\n" << " nu = " << nus[j][k] << "\n" << " rho = " << rhos[j][k] << "\n" << (useMaxError_ ? ": error" : ": max error ") << (useMaxError_ ? rmsError :maxError) ); } } Cube sabrParametersCube(optionDates, swapTenors, optionTimes, swapLengths, 8); sabrParametersCube.setLayer(0, alphas); sabrParametersCube.setLayer(1, betas); sabrParametersCube.setLayer(2, nus); sabrParametersCube.setLayer(3, rhos); sabrParametersCube.setLayer(4, forwards); sabrParametersCube.setLayer(5, errors); sabrParametersCube.setLayer(6, maxErrors); sabrParametersCube.setLayer(7, endCriteria); return sabrParametersCube; }