NonstandardSwap::NonstandardSwap(const VanillaSwap &fromVanilla) : Swap(2), type_((VanillaSwap::Type)fromVanilla.type()), fixedNominal_(std::vector<Real>(fromVanilla.fixedLeg().size(), fromVanilla.nominal())), floatingNominal_(std::vector<Real>(fromVanilla.floatingLeg().size(), fromVanilla.nominal())), fixedSchedule_(fromVanilla.fixedSchedule()), fixedRate_(std::vector<Real>(fromVanilla.fixedLeg().size(), fromVanilla.fixedRate())), fixedDayCount_(fromVanilla.fixedDayCount()), floatingSchedule_(fromVanilla.floatingSchedule()), iborIndex_(fromVanilla.iborIndex()), spread_(std::vector<Real>(fromVanilla.floatingLeg().size(), fromVanilla.spread())), gearing_(std::vector<Real>(fromVanilla.floatingLeg().size(), 1.0)), singleSpreadAndGearing_(true), floatingDayCount_(fromVanilla.floatingDayCount()), paymentConvention_(fromVanilla.paymentConvention()), intermediateCapitalExchange_(false), finalCapitalExchange_(false) { init(); }
void LgmSwaptionEngineAD::calculate() const { // collect data needed for core computation routine QL_REQUIRE(arguments_.settlementType == Settlement::Physical, "cash-settled swaptions not yet implemented ..."); Date settlement = model_->termStructure()->referenceDate(); if (arguments_.exercise->dates().back() <= settlement) { // swaption is expired, possibly generated swap is not // valued results_.value = 0.0; return; } int idxMax = static_cast<int>(arguments_.exercise->dates().size()) - 1; int minIdxAlive = static_cast<int>( std::upper_bound(arguments_.exercise->dates().begin(), arguments_.exercise->dates().end(), settlement) - arguments_.exercise->dates().begin()); VanillaSwap swap = *arguments_.swap; int callput = arguments_.type == VanillaSwap::Payer ? 1 : -1; Schedule fixedSchedule = swap.fixedSchedule(); Schedule floatSchedule = swap.floatingSchedule(); Date expiry0; std::vector<int> fix_startidxes, float_startidxes; std::vector<Date> expiryDates; for (int idx = minIdxAlive; idx <= idxMax; ++idx) { expiry0 = arguments_.exercise->dates()[idx]; expiryDates.push_back(expiry0); Size j1 = std::upper_bound(fixedSchedule.dates().begin(), fixedSchedule.dates().end(), expiry0 - 1) - fixedSchedule.dates().begin(); Size k1 = std::upper_bound(floatSchedule.dates().begin(), floatSchedule.dates().end(), expiry0 - 1) - floatSchedule.dates().begin(); fix_startidxes.push_back(j1); float_startidxes.push_back(k1); } std::vector<double> float_mults, index_acctimes, float_spreads, fix_cpn; std::vector<Date> floatt1Dates, floatt2Dates, floattpDates; std::vector<Date> fixtpDates; for (Size i = 0; i < arguments_.floatingFixingDates.size(); ++i) { float_mults.push_back(arguments_.nominal * arguments_.floatingAccrualTimes[i]); float_spreads.push_back(arguments_.floatingSpreads[i]); boost::shared_ptr<IborIndex> index = arguments_.swap->iborIndex(); Date d1 = index->valueDate(arguments_.floatingFixingDates[i]); Date d2 = index->maturityDate(d1); double acctime = index->dayCounter().yearFraction(d1, d2, d1, d2); floatt1Dates.push_back(d1); floatt2Dates.push_back(d2); floattpDates.push_back(arguments_.floatingPayDates[i]); index_acctimes.push_back(acctime); } for (Size i = 0; i < arguments_.fixedCoupons.size(); ++i) { fix_cpn.push_back(arguments_.fixedCoupons[i]); fixtpDates.push_back(arguments_.fixedPayDates[i]); } // join all dates and fill index vectors std::vector<Date> allDates; std::vector<double> allTimes; // with settlement as first entry ! std::vector<int> expiries, floatt1s, floatt2s, floattps, fixtps; std::vector<double> modpar; allDates.reserve(expiryDates.size() + floatt1Dates.size() + floatt2Dates.size() + floattpDates.size() + fixtpDates.size()); allTimes.reserve(allDates.size()); modpar.reserve(3 * allDates.size()); allDates.push_back(settlement); allDates.insert(allDates.end(), expiryDates.begin(), expiryDates.end()); allDates.insert(allDates.end(), floatt1Dates.begin(), floatt1Dates.end()); allDates.insert(allDates.end(), floatt2Dates.begin(), floatt2Dates.end()); allDates.insert(allDates.end(), floattpDates.begin(), floattpDates.end()); allDates.insert(allDates.end(), fixtpDates.begin(), fixtpDates.end()); std::sort(allDates.begin(), allDates.end()); allDates.erase(unique(allDates.begin(), allDates.end()), allDates.end()); for (Size i = 0; i < allDates.size(); ++i) { allTimes.push_back( model_->termStructure()->timeFromReference(allDates[i])); } for (Size i = 0; i < allDates.size(); ++i) { modpar.push_back(model_->parametrization()->H(allTimes[i])); } for (Size i = 0; i < allDates.size(); ++i) { modpar.push_back(model_->parametrization()->zeta(allTimes[i])); } for (Size i = 0; i < allDates.size(); ++i) { modpar.push_back(model_->termStructure()->discount(allTimes[i])); } for (Size i = 0; i < expiryDates.size(); ++i) { expiries.push_back( std::find(allDates.begin(), allDates.end(), expiryDates[i]) - allDates.begin()); } for (Size i = 0; i < floatt1Dates.size(); ++i) { floatt1s.push_back( std::find(allDates.begin(), allDates.end(), floatt1Dates[i]) - allDates.begin()); } for (Size i = 0; i < floatt2Dates.size(); ++i) { floatt2s.push_back( std::find(allDates.begin(), allDates.end(), floatt2Dates[i]) - allDates.begin()); } for (Size i = 0; i < floattpDates.size(); ++i) { floattps.push_back( std::find(allDates.begin(), allDates.end(), floattpDates[i]) - allDates.begin()); } for (Size i = 0; i < fixtpDates.size(); ++i) { fixtps.push_back( std::find(allDates.begin(), allDates.end(), fixtpDates[i]) - allDates.begin()); } // call core computation routine and set results int ntimes = allTimes.size(); int nexpiries = expiries.size(); int nfloats = floatt1s.size(); int nfixs = fix_cpn.size(); double res = 0.0; std::vector<Real> dres(3*ntimes); int integration_pts = integrationPoints_; double std_devs = stddevs_; lgm_swaption_engine_ad_(&ntimes, &allTimes[0], &modpar[0], &nexpiries, &expiries[0], &callput, &nfloats, &float_startidxes[0], &float_mults[0], &index_acctimes[0], &float_spreads[0], &floatt1s[0], &floatt2s[0], &floattps[0], &fix_startidxes[0], &nfixs, &fix_cpn[0], &fixtps[0], &integration_pts, &std_devs, &res, &dres[0]); results_.value = res; std::vector<Real> H_sensitivity(dres.begin(),dres.begin()+ntimes); std::vector<Real> zeta_sensitivity(dres.begin()+ntimes,dres.begin()+2*ntimes); std::vector<Real> discount_sensitivity(dres.begin()+2*ntimes,dres.begin()+3*ntimes); results_.additionalResults["sensitivityTimes"] = allTimes; results_.additionalResults["sensitivityH"] = H_sensitivity; results_.additionalResults["sensitivityZeta"] = zeta_sensitivity; results_.additionalResults["sensitivityDiscount"] = discount_sensitivity; }
void BlackStyleSwaptionEngine<Spec>::calculate() const { static const Spread basisPoint = 1.0e-4; Date exerciseDate = arguments_.exercise->date(0); // the part of the swap preceding exerciseDate should be truncated // to avoid taking into account unwanted cashflows VanillaSwap swap = *arguments_.swap; Rate strike = swap.fixedRate(); // using the discounting curve // swap.iborIndex() might be using a different forwarding curve swap.setPricingEngine(boost::shared_ptr<PricingEngine>(new DiscountingSwapEngine(discountCurve_, false))); Rate atmForward = swap.fairRate(); // Volatilities are quoted for zero-spreaded swaps. // Therefore, any spread on the floating leg must be removed // with a corresponding correction on the fixed leg. if (swap.spread()!=0.0) { Spread correction = swap.spread() * std::fabs(swap.floatingLegBPS()/swap.fixedLegBPS()); strike -= correction; atmForward -= correction; results_.additionalResults["spreadCorrection"] = correction; } else { results_.additionalResults["spreadCorrection"] = 0.0; } results_.additionalResults["strike"] = strike; results_.additionalResults["atmForward"] = atmForward; // using the discounting curve swap.setPricingEngine(boost::shared_ptr<PricingEngine>( new DiscountingSwapEngine(discountCurve_, false))); Real annuity; switch(arguments_.settlementType) { case Settlement::Physical: { annuity = std::fabs(swap.fixedLegBPS())/basisPoint; break; } case Settlement::Cash: { const Leg& fixedLeg = swap.fixedLeg(); boost::shared_ptr<FixedRateCoupon> firstCoupon = boost::dynamic_pointer_cast<FixedRateCoupon>(fixedLeg[0]); DayCounter dayCount = firstCoupon->dayCounter(); Real fixedLegCashBPS = CashFlows::bps(fixedLeg, InterestRate(atmForward, dayCount, Compounded, Annual), false, discountCurve_->referenceDate()) ; annuity = std::fabs(fixedLegCashBPS/basisPoint); break; } default: QL_FAIL("unknown settlement type"); } results_.additionalResults["annuity"] = annuity; Time swapLength = vol_->swapLength(swap.floatingSchedule().dates().front(), swap.floatingSchedule().dates().back()); results_.additionalResults["swapLength"] = swapLength; Real variance = vol_->blackVariance(exerciseDate, swapLength, strike); // once the deprecated methods allowing to override the displacement // are gone, we can avoid this and directly read the displacement // from the volatility structure Real displacement = displacement_ == Null<Real>() ? vol_->shift(exerciseDate, swapLength) : displacement_; Real stdDev = std::sqrt(variance); results_.additionalResults["stdDev"] = stdDev; Option::Type w = (arguments_.type==VanillaSwap::Payer) ? Option::Call : Option::Put; results_.value = Spec().value(w, strike, atmForward, stdDev, annuity, displacement); Time exerciseTime = vol_->timeFromReference(exerciseDate); results_.additionalResults["vega"] = Spec().vega( strike, atmForward, stdDev, exerciseTime, annuity, displacement); }
void Gaussian1dSwaptionEngine::calculate() const { QL_REQUIRE(arguments_.settlementType == Settlement::Physical, "cash-settled swaptions not yet implemented ..."); Date settlement = model_->termStructure()->referenceDate(); if (arguments_.exercise->dates().back() <= settlement) { // swaption is expired, possibly generated swap is not // valued results_.value = 0.0; return; } int idx = static_cast<int>(arguments_.exercise->dates().size()) - 1; int minIdxAlive = static_cast<int>( std::upper_bound(arguments_.exercise->dates().begin(), arguments_.exercise->dates().end(), settlement) - arguments_.exercise->dates().begin()); VanillaSwap swap = *arguments_.swap; Option::Type type = arguments_.type == VanillaSwap::Payer ? Option::Call : Option::Put; Schedule fixedSchedule = swap.fixedSchedule(); Schedule floatSchedule = swap.floatingSchedule(); Array npv0(2 * integrationPoints_ + 1, 0.0), npv1(2 * integrationPoints_ + 1, 0.0); Array z = model_->yGrid(stddevs_, integrationPoints_); Array p(z.size(), 0.0); Date expiry1 = Null<Date>(), expiry0; Time expiry1Time = Null<Real>(), expiry0Time; do { if (idx == minIdxAlive - 1) expiry0 = settlement; else expiry0 = arguments_.exercise->dates()[idx]; expiry0Time = std::max( model_->termStructure()->timeFromReference(expiry0), 0.0); Size j1 = std::upper_bound(fixedSchedule.dates().begin(), fixedSchedule.dates().end(), expiry0 - 1) - fixedSchedule.dates().begin(); Size k1 = std::upper_bound(floatSchedule.dates().begin(), floatSchedule.dates().end(), expiry0 - 1) - floatSchedule.dates().begin(); // a lazy object is not thread safe, neither is the caching // in gsrprocess. therefore we trigger computations here such // that neither lazy object recalculation nor write access // during caching occurs in the parallized loop below. // this is known to work for the gsr and markov functional // model implementations of Gaussian1dModel #ifdef _OPENMP if (expiry0 > settlement) { for (Size l = k1; l < arguments_.floatingCoupons.size(); l++) { model_->forwardRate(arguments_.floatingFixingDates[l], expiry0, 0.0, arguments_.swap->iborIndex()); model_->zerobond(arguments_.floatingPayDates[l], expiry0, 0.0, discountCurve_); } for (Size l = j1; l < arguments_.fixedCoupons.size(); l++) { model_->zerobond(arguments_.fixedPayDates[l], expiry0, 0.0, discountCurve_); } model_->numeraire(expiry0Time, 0.0, discountCurve_); } #endif #pragma omp parallel for default(shared) firstprivate(p) if(expiry0>settlement) for (Size k = 0; k < (expiry0 > settlement ? npv0.size() : 1); k++) { Real price = 0.0; if (expiry1Time != Null<Real>()) { Array yg = model_->yGrid(stddevs_, integrationPoints_, expiry1Time, expiry0Time, expiry0 > settlement ? z[k] : 0.0); CubicInterpolation payoff0( z.begin(), z.end(), npv1.begin(), CubicInterpolation::Spline, true, CubicInterpolation::Lagrange, 0.0, CubicInterpolation::Lagrange, 0.0); for (Size i = 0; i < yg.size(); i++) { p[i] = payoff0(yg[i], true); } CubicInterpolation payoff1( z.begin(), z.end(), p.begin(), CubicInterpolation::Spline, true, CubicInterpolation::Lagrange, 0.0, CubicInterpolation::Lagrange, 0.0); for (Size i = 0; i < z.size() - 1; i++) { price += model_->gaussianShiftedPolynomialIntegral( 0.0, payoff1.cCoefficients()[i], payoff1.bCoefficients()[i], payoff1.aCoefficients()[i], p[i], z[i], z[i], z[i + 1]); } if (extrapolatePayoff_) { if (flatPayoffExtrapolation_) { price += model_->gaussianShiftedPolynomialIntegral( 0.0, 0.0, 0.0, 0.0, p[z.size() - 2], z[z.size() - 2], z[z.size() - 1], 100.0); price += model_->gaussianShiftedPolynomialIntegral( 0.0, 0.0, 0.0, 0.0, p[0], z[0], -100.0, z[0]); } else { if (type == Option::Call) price += model_->gaussianShiftedPolynomialIntegral( 0.0, payoff1.cCoefficients()[z.size() - 2], payoff1.bCoefficients()[z.size() - 2], payoff1.aCoefficients()[z.size() - 2], p[z.size() - 2], z[z.size() - 2], z[z.size() - 1], 100.0); if (type == Option::Put) price += model_->gaussianShiftedPolynomialIntegral( 0.0, payoff1.cCoefficients()[0], payoff1.bCoefficients()[0], payoff1.aCoefficients()[0], p[0], z[0], -100.0, z[0]); } } } npv0[k] = price; if (expiry0 > settlement) { Real floatingLegNpv = 0.0; for (Size l = k1; l < arguments_.floatingCoupons.size(); l++) { floatingLegNpv += arguments_.nominal * arguments_.floatingAccrualTimes[l] * (arguments_.floatingSpreads[l] + model_->forwardRate( arguments_.floatingFixingDates[l], expiry0, z[k], arguments_.swap->iborIndex())) * model_->zerobond(arguments_.floatingPayDates[l], expiry0, z[k], discountCurve_); } Real fixedLegNpv = 0.0; for (Size l = j1; l < arguments_.fixedCoupons.size(); l++) { fixedLegNpv += arguments_.fixedCoupons[l] * model_->zerobond(arguments_.fixedPayDates[l], expiry0, z[k], discountCurve_); } npv0[k] = std::max(npv0[k], (type == Option::Call ? 1.0 : -1.0) * (floatingLegNpv - fixedLegNpv) / model_->numeraire(expiry0Time, z[k], discountCurve_)); } } npv1.swap(npv0); expiry1 = expiry0; expiry1Time = expiry0Time; } while (--idx >= minIdxAlive - 1); results_.value = npv1[0] * model_->numeraire(0.0, 0.0, discountCurve_); }