25Array
max(Array x,
const Real b) {
26 std::transform(x.begin(), x.end(), x.begin(), [b](
const Real u) { return std::max(u, b); });
29Array
max(Array x,
const Array& y) {
30 QL_REQUIRE(x.size() == y.size(),
31 "max(Array,Array) requires arrays of equal size, got " << x.size() <<
" and " << y.size());
32 for (Size i = 0; i < x.size(); ++i) {
33 x[i] = std::max(x[i], y[i]);
40 const Real
sy,
const Size ny,
const Real
sx,
const Size nx,
41 const Handle<YieldTermStructure>& discountCurve,
42 const Method method,
const Real singleSwaptionThreshold)
44 singleSwaptionThreshold_(singleSwaptionThreshold) {}
47 const Size fixIndex,
const Real fltPayTime,
48 const Real fixPayTime)
const {
50 Real om =
type == VanillaSwap::Payer ? -1.0 : 1.0;
51 if (fixIndex != Null<Size>()) {
52 if (!QuantLib::close_enough(
fixedNominal[fixIndex], 0.0))
56 if (fltIndex != Null<Size>()) {
60 fixing = std::min(fixing,
cappedRate[fltIndex]);
71 Date today =
model()->parametrization()->termStructure()->referenceDate();
76 QL_REQUIRE(
fixedNominal.size() > 0,
"NumericLgmFlexiSwapEngine::calculate(): fixed nominal size is zero");
77 QL_REQUIRE(
floatingNominal.size() > 0,
"NumericLgmFlexiSwapEngine::calculate(): floating nominal size is zero");
79 std::vector<Real> times;
80 std::vector<Date> dates;
81 std::vector<Size> fixCpnIndex, fltCpnIndex;
82 std::vector<Real> fixPayTime, fltPayTime;
83 Size firstAliveIndex = Null<Size>();
87 if (firstAliveIndex == Null<Size>())
89 times.push_back(
model()->parametrization()->termStructure()->timeFromReference(d));
91 fltCpnIndex.push_back(i);
92 fltPayTime.push_back(
model()->parametrization()->termStructure()->timeFromReference(
floatingPayDates[i]));
93 if (i % legRatio == 0) {
94 Size idx =
static_cast<Size
>(i / legRatio);
95 fixCpnIndex.push_back(idx);
99 fixCpnIndex.push_back(Null<Size>());
100 fixPayTime.push_back(Null<Real>());
105 int n = times.size();
109 std::vector<Real> swaptionVolTmp;
110 std::vector<Size> swaptionStartIdx, swaptionEndIdx;
120 Real currentVolUpper =
123 if (!QuantLib::close_enough(currentVolUpper, currentVolLower)) {
126 if (nextNotional < currentVolUpper && !QuantLib::close_enough(currentVolLower, currentVolUpper)) {
127 Real tmpVol = std::min(currentVolUpper - nextNotional, currentVolUpper - currentVolLower);
128 if (!QuantLib::close_enough(tmpVol, 0.0)) {
129 swaptionStartIdx.push_back(i);
130 swaptionEndIdx.push_back(j + 1);
131 swaptionVolTmp.push_back(tmpVol);
132 currentVolUpper = std::max(nextNotional, currentVolLower);
136 QL_REQUIRE(QuantLib::close_enough(currentVolUpper, currentVolLower),
137 "NumericLgmFlexiSwapEngine:calculate(): currentVolUpper ("
138 << currentVolUpper <<
") does not match currentVolLower (" << currentVolLower
139 <<
"), this is unexpected");
143 int m = swaptionVolTmp.size();
148 Real fullGridSwaptions = 0.0;
149 for (
int i = 0; i < m; ++i) {
150 fullGridSwaptions +=
static_cast<Size
>(swaptionEndIdx[i] - swaptionStartIdx[i]);
152 fullGridSwaptions /=
static_cast<Real
>(n);
163 std::vector<Array> underlyingMultiplier(n, Array(m, 0.0));
165 std::vector<Array> exerciseIndicator(n, Array(m, 0.0));
169 for (
int i = 0; i < m; ++i) {
170 notionals[i] = swaptionVolTmp[i];
171 for (Size j = swaptionStartIdx[i]; j < swaptionEndIdx[i]; ++j) {
172 Size index = j * legRatio;
174 index -= firstAliveIndex;
175 exerciseIndicator[index][i] = 1.0;
176 for (Size k = 0; k < legRatio; ++k) {
177 underlyingMultiplier[index + k][i] = swaptionVolTmp[i];
191 std::vector<Array> u_a, v_a;
192 std::vector<Real> u_s, v_s;
197 u_a.resize(
gridSize(), Array(m, 0.0));
198 v_a.resize(
gridSize(), Array(m, 0.0));
201 Real undValAll0 = 0.0;
202 int undValAllIdx = n + 1;
203 Array value0(m, 0.0);
209 std::vector<Real> uAll(
gridSize(), 0.0);
216 QL_REQUIRE(swaptionEndIdx[sw] * legRatio >= firstAliveIndex,
217 "swaptionEndIndex[" << sw <<
"] * legRatio (" << legRatio <<
") < firstAliveIndex ("
218 << firstAliveIndex <<
") - this is unexpected.");
219 n = swaptionEndIdx[sw] * legRatio - firstAliveIndex;
223 for (Size k = 0; k <
gridSize(); ++k) {
224 Real tmp =
underlyingValue(states[k], times[n - 1], dates[n - 1], fltCpnIndex[n - 1], fixCpnIndex[n - 1],
225 fltPayTime[n - 1], fixPayTime[n - 1]);
227 if (n < undValAllIdx) {
231 u_s[k] = tmp * underlyingMultiplier[n - 1][sw];
232 v_s[k] = exerciseIndicator[n - 1][sw] * std::max(-phi * u_s[k], 0.0);
234 u_a[k] = tmp * underlyingMultiplier[n - 1];
235 v_a[k] = exerciseIndicator[n - 1] *
max(-phi * u_a[k], 0.0);
245 QL_REQUIRE(swaptionStartIdx[sw] * legRatio >= firstAliveIndex,
246 "swaptionStartIndex[" << sw <<
"] * legRatio (" << legRatio <<
") < firstAliveIndex ("
247 << firstAliveIndex <<
") - this is unexpected.");
248 minIndex = swaptionStartIdx[sw] * legRatio - firstAliveIndex;
251 for (
int j = n - 1; j > minIndex; j--) {
255 u_s =
rollback(u_s, times[j], times[j - 1]);
256 v_s =
rollback(v_s, times[j], times[j - 1]);
258 u_a =
rollback(u_a, times[j], times[j - 1], Array(m, 0.0));
259 v_a =
rollback(v_a, times[j], times[j - 1], Array(m, 0.0));
261 if (j < undValAllIdx) {
262 uAll =
rollback(uAll, times[j], times[j - 1]);
265 for (Size k = 0; k <
gridSize(); ++k) {
266 Real tmp =
underlyingValue(states[k], times[j - 1], dates[j - 1], fltCpnIndex[j - 1],
267 fixCpnIndex[j - 1], fltPayTime[j - 1], fixPayTime[j - 1]);
268 uAll[k] += (j < undValAllIdx ? tmp *
floatingNominal[fltCpnIndex[j - 1]] : 0.0);
270 u_s[k] += tmp * underlyingMultiplier[j - 1][sw];
271 v_s[k] = exerciseIndicator[j - 1][sw] * std::max(v_s[k], -phi * u_s[k]) +
272 (1.0 - exerciseIndicator[j - 1][sw]) * v_s[k];
274 u_a[k] += tmp * underlyingMultiplier[j - 1];
275 v_a[k] = exerciseIndicator[j - 1] *
max(v_a[k], -phi * u_a[k]) +
276 (1.0 - exerciseIndicator[j - 1]) * v_a[k];
284 v_s =
rollback(v_s, times[minIndex], 0.0);
286 v_a =
rollback(v_a, times[minIndex], 0.0, Array(m, 0.0));
288 uAll =
rollback(uAll, times[minIndex], 0.0);
291 undValAllIdx = minIndex + 1;
300 undValAll0 += uAll[0];
306 Size minFltCpnIdx = fltCpnIndex.empty() ? 0 : *std::min_element(fltCpnIndex.begin(), fltCpnIndex.end());
307 Size minFixCpnIdx = fixCpnIndex.empty() ? 0 : *std::min_element(fixCpnIndex.begin(), fixCpnIndex.end());
320 "NumericLgmFlexiSwapEngineBase: no floating coupon provided for fixing date "
329 Real sumOptions = std::accumulate(value0.begin(), value0.end(), 0.0);
358 return std::make_pair(phi * sumOptions + undValAll0, undValAll0);
363 const Real
sy,
const Size ny,
const Real
sx,
const Size nx,
364 const Handle<YieldTermStructure>& discountCurve,
365 const Method method,
const Real singleSwaptionThreshold)
367 registerWith(this->
model());
397 results_.underlyingValue = result.second;
const Instrument::results * results_
Numerical convolution solver for the LGM model.
std::vector< ValueType > rollback(const std::vector< ValueType > &v, const Real t1, const Real t0, const ValueType zero=ValueType(0.0)) const
const QuantLib::ext::shared_ptr< LinearGaussMarkovModel > & model() const
std::vector< Real > stateGrid(const Real t) const
Numerical engine for flexi swaps in the LGM model.
std::vector< Real > cappedRate
std::vector< Date > floatingResetDates
NumericLgmFlexiSwapEngineBase(const QuantLib::ext::shared_ptr< LinearGaussMarkovModel > &model, const Real sy, const Size ny, const Real sx, const Size nx, const Handle< YieldTermStructure > &discountCurve=Handle< YieldTermStructure >(), const Method method=Method::Automatic, const Real singleSwaptionThreshold=20.0)
const Handle< YieldTermStructure > discountCurve_
QuantLib::ext::shared_ptr< IborIndex > iborIndex
std::vector< Real > floatingGearings
QuantLib::ext::shared_ptr< LgmImpliedYieldTermStructure > iborModelCurve_
std::pair< Real, Real > calculate() const
std::vector< Real > floatingSpreads
QuantLib::ext::shared_ptr< IborIndex > iborModelIndex_
std::vector< Date > floatingFixingDates
std::vector< Real > flooredRate
Real underlyingValue(const Real, const Real, const Date &, const Size, const Size, const Real, const Real) const
std::vector< Date > fixedPayDates
std::vector< Real > fixedNominal
std::vector< Date > fixedResetDates
std::vector< Real > floatingNominal
QuantLib::Position::Type optionPosition
const Real singleSwaptionThreshold_
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
NumericLgmFlexiSwapEngine(const QuantLib::ext::shared_ptr< LinearGaussMarkovModel > &model, const Real sy, const Size ny, const Real sx, const Size nx, const Handle< YieldTermStructure > &discountCurve=Handle< YieldTermStructure >(), const Method method=Method::Automatic, const Real singleSwaptionThreshold=20.0)
void calculate() const override
std::map< std::string, boost::any > getAdditionalResultsMap(const LgmCalibrationInfo &info)
CompiledFormula max(CompiledFormula x, const CompiledFormula &y)
numeric engine for flexi swaps in the LGM model
JY INF index sigma component.
Swap::arguments * arguments_