21#include <ql/cashflows/coupon.hpp>
26 const Real
sy,
const Size ny,
const Real
sx,
const Size nx,
27 const Handle<Quote>& minCpr,
const Handle<Quote>& maxCpr,
28 const Handle<YieldTermStructure>& discountCurve,
29 const Method method,
const Real singleSwaptionThreshold)
31 minCpr_(minCpr), maxCpr_(maxCpr) {
32 registerWith(this->
model());
39Real getNotional(
const std::vector<Real> nominals,
const std::vector<Date> dates,
const Date& d) {
40 QL_REQUIRE(nominals.size() + 1 == dates.size(),
"getNominal(): nominals size (" << nominals.size()
41 <<
") + 1 must be dates size ("
42 << dates.size() <<
")");
43 if (d < dates.front() || d >= dates.back())
45 Size l = std::upper_bound(dates.begin(), dates.end(), d) - dates.begin();
46 return nominals[l - 1];
51 Date today = Settings::instance().evaluationDate();
53 Real currentLowerNotionalAfterPrepayment = 0.0, currentUpperNotionalAfterPrepayment = 0.0,
54 lastAggregatePrincipal = 0.0;
55 std::vector<Real> tmpLowerNotionalBound, tmpUpperNotionalBound;
56 Real effectiveMinCpr =
minCpr_->value() /
static_cast<Real
>(
arguments_.trancheNominalFrequency);
57 Real effectiveMaxCpr =
maxCpr_->value() /
static_cast<Real
>(
arguments_.trancheNominalFrequency);
58 for (Size i = 0; i <
arguments_.trancheNominalDates.size() - 1; ++i) {
59 Real aggregatePrincipal = 0.0;
60 for (Size j = 0; j <
arguments_.trancheNominals.size(); ++j)
61 aggregatePrincipal +=
arguments_.trancheNominals[j][i];
64 currentUpperNotionalAfterPrepayment = aggregatePrincipal;
65 currentLowerNotionalAfterPrepayment = aggregatePrincipal;
69 Real amortisationRate =
70 QuantLib::close_enough(aggregatePrincipal, 0.0) ? 0.0 : (aggregatePrincipal / lastAggregatePrincipal);
72 currentUpperNotionalAfterPrepayment =
73 currentUpperNotionalAfterPrepayment *
74 std::max(amortisationRate - (
arguments_.trancheNominalDates[i] > today ? effectiveMinCpr : 0.0), 0.0);
75 currentLowerNotionalAfterPrepayment =
76 currentLowerNotionalAfterPrepayment *
77 std::max(amortisationRate - (
arguments_.trancheNominalDates[i] > today ? effectiveMaxCpr : 0.0), 0.0);
81 Real subordinatedPrincipal = 0;
83 subordinatedPrincipal +=
arguments_.trancheNominals[k][i];
86 tmpLowerNotionalBound.push_back(
87 std::min(std::max(currentLowerNotionalAfterPrepayment - subordinatedPrincipal, 0.0),
89 tmpUpperNotionalBound.push_back(
90 std::min(std::max(currentUpperNotionalAfterPrepayment - subordinatedPrincipal, 0.0),
93 lastAggregatePrincipal = aggregatePrincipal;
97 std::vector<Real> lowerNotionalFixedBound, upperNotionalFixedBound, upperNotionalFloatingBound;
98 for (Size i = 0; i <
arguments_.fixedResetDates.size(); ++i) {
99 lowerNotionalFixedBound.push_back(
100 getNotional(tmpLowerNotionalBound,
arguments_.trancheNominalDates,
arguments_.fixedResetDates[i]));
101 upperNotionalFixedBound.push_back(
102 getNotional(tmpUpperNotionalBound,
arguments_.trancheNominalDates,
arguments_.fixedResetDates[i]));
107 upperNotionalFloatingBound.resize(upperNotionalFixedBound.size() * ratio);
109 std::generate(upperNotionalFloatingBound.begin(), upperNotionalFloatingBound.end(),
110 [i, &upperNotionalFixedBound, ratio]()
mutable { return upperNotionalFixedBound[i++ / ratio]; });
113 std::vector<Real> upperFixedCoupons, upperFloatingCoupons;
114 for (Size i = 0; i <
arguments_.fixedLeg.size(); ++i) {
115 auto cp = QuantLib::ext::dynamic_pointer_cast<QuantLib::Coupon>(
arguments_.fixedLeg[i]);
116 upperFixedCoupons.push_back(cp->accrualPeriod() * cp->rate() * upperNotionalFixedBound[i]);
118 for (Size i = 0; i <
arguments_.floatingLeg.size(); ++i) {
119 auto cp = QuantLib::ext::dynamic_pointer_cast<QuantLib::Coupon>(
arguments_.floatingLeg[i]);
121 upperFloatingCoupons.push_back(cp->accrualPeriod() * cp->rate() * upperNotionalFloatingBound[i]);
123 upperFloatingCoupons.push_back(Null<Real>());
128 QuantLib::Position::Type flexiOptionPosition =
129 arguments_.type == VanillaSwap::Payer ? QuantLib::Position::Long : QuantLib::Position::Short;
const Instrument::results * results_
const QuantLib::ext::shared_ptr< LinearGaussMarkovModel > & model() const
void calculate() const override
NumericLgmBgsFlexiSwapEngine(const QuantLib::ext::shared_ptr< LinearGaussMarkovModel > &model, const Real sy, const Size ny, const Real sx, const Size nx, const Handle< Quote > &minCpr, const Handle< Quote > &maxCpr, const Handle< YieldTermStructure > &discountCurve=Handle< YieldTermStructure >(), const Method method=Method::Automatic, const Real singleSwaptionThreshold=20.0)
const Handle< Quote > minCpr_
const Handle< Quote > maxCpr_
Numerical engine for flexi swaps in the LGM model.
std::vector< Real > cappedRate
std::vector< Date > floatingResetDates
const Handle< YieldTermStructure > discountCurve_
QuantLib::ext::shared_ptr< IborIndex > iborIndex
std::vector< Real > floatingGearings
std::pair< Real, Real > calculate() const
std::vector< Real > floatingSpreads
std::vector< Date > floatingFixingDates
std::vector< Real > flooredRate
std::vector< Date > fixedPayDates
std::vector< Real > fixedNominal
std::vector< Date > fixedResetDates
std::vector< Real > floatingNominal
QuantLib::Position::Type optionPosition
std::vector< Real > floatingCoupons
std::vector< bool > notionalCanBeDecreased
std::vector< Real > lowerNotionalBound
std::vector< Real > fixedRate
std::vector< Time > floatingAccrualTimes
std::vector< Real > fixedCoupons
std::vector< Date > floatingPayDates
std::map< std::string, boost::any > getAdditionalResultsMap(const LgmCalibrationInfo &info)
numeric engine for balance guaranteed swaps using a flexi swap proxy in the LGM model
JY INF index sigma component.
Swap::arguments * arguments_