21#include <ql/cashflows/floatingratecoupon.hpp>
22#include <ql/quotes/simplequote.hpp>
30 const std::string& baseCcy,
const std::map<std::string, Handle<YieldTermStructure>>& discountCurves,
31 const std::map<std::string, Handle<Quote>>& fxSpots,
const Handle<DefaultProbabilityTermStructure>& defaultCurve,
32 const Handle<Quote>& recoveryRate,
const Size maxGapDays,
const Size maxDiscretisationPoints)
33 : baseCcy_(baseCcy), discountCurves_(discountCurves), fxSpots_(fxSpots), defaultCurve_(defaultCurve),
34 recoveryRate_(recoveryRate), maxGapDays_(maxGapDays), maxDiscretisationPoints_(maxDiscretisationPoints) {
35 QL_REQUIRE(maxGapDays == Null<Size>() || maxGapDays >= 1,
36 "invalid maxGapDays (" << maxGapDays <<
"), must be >= 1");
38 "invalid maxDiscretisationPoints (" << maxDiscretisationPoints <<
"), must be >= 3");
40 registerWith(d.second);
42 registerWith(s.second);
45 fxSpots_[
baseCcy_] = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(1.0));
63 const Date&
referenceDate,
const Date& protectionStart,
const Date& protectionEnd,
64 const std::vector<Leg>& underlying,
const Size maxGapDays,
const Size maxDiscretisationPoints) {
67 "protection end (" << protectionEnd <<
") must be > reference date (" <<
referenceDate <<
")");
71 std::vector<Date> accrualDates;
72 for (
auto const& l : underlying) {
73 for (
auto const& c : l) {
74 if (
auto f = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(c)) {
75 accrualDates.push_back(f->accrualEndDate());
82 accrualDates.push_back(std::max(protectionStart,
referenceDate));
83 accrualDates.push_back(protectionEnd);
85 std::sort(accrualDates.begin(), accrualDates.end());
86 auto it = std::unique(accrualDates.begin(), accrualDates.end());
87 accrualDates.resize(it - accrualDates.begin());
89 auto itStart = std::lower_bound(accrualDates.begin(), accrualDates.end(),
referenceDate);
90 auto itEnd = std::upper_bound(accrualDates.begin(), accrualDates.end(), protectionEnd);
92 QL_REQUIRE(std::distance(itStart, itEnd) >= 2,
"got invalid discretisationGrid for RPA, this is unexpected");
94 std::vector<Date> gridDates(itStart, itEnd);
98 if (maxGapDays != Null<Size>()) {
101 Size refiningIterations = 0;
104 for (
auto it = gridDates.begin(); it < gridDates.end() - 1; ++it) {
105 if (*(it + 1) - *it > std::max<int>(1, maxGapDays)) {
106 it = gridDates.insert(it + 1, *it + (*(it + 1) - *it) / 2);
110 }
while (refining && ++refiningIterations < 100);
111 QL_REQUIRE(refiningIterations < 100,
"discretisationGrid refinement failed, this is unexpected");
127 Size currentNumberOfDiscretisationPoints = gridDates.size() - 1,
128 previousNumberOfDiscretisationPoints = QL_MAX_INTEGER;
130 while (maxDiscretisationPoints != Null<Size>() && currentNumberOfDiscretisationPoints > maxDiscretisationPoints &&
131 currentNumberOfDiscretisationPoints < previousNumberOfDiscretisationPoints) {
133 previousNumberOfDiscretisationPoints = currentNumberOfDiscretisationPoints;
134 Size currentLeftIndex = 0, currentRightIndex = gridDates.size() - 1;
135 bool nextErasureOnLeft =
true, canRemoveFurtherPointsInPass =
true;
137 while (currentNumberOfDiscretisationPoints > maxDiscretisationPoints && canRemoveFurtherPointsInPass) {
138 if (nextErasureOnLeft) {
139 if (gridDates.size() >= currentLeftIndex + 4 && currentLeftIndex + 3 <= currentRightIndex) {
140 gridDates.erase(std::next(gridDates.begin(), currentLeftIndex + 1),
141 std::next(gridDates.begin(), currentLeftIndex + 3));
142 currentNumberOfDiscretisationPoints -= 2;
143 currentRightIndex -= 2;
145 nextErasureOnLeft =
false;
147 canRemoveFurtherPointsInPass =
false;
150 if (currentRightIndex >= 3 && currentLeftIndex + 3 <= currentRightIndex) {
151 gridDates.erase(std::next(gridDates.begin(), currentRightIndex - 2),
152 std::next(gridDates.begin(), currentRightIndex));
153 currentNumberOfDiscretisationPoints -= 2;
154 currentRightIndex -= 3;
155 nextErasureOnLeft =
true;
157 canRemoveFurtherPointsInPass =
false;
171 "RiskParticipationAgreementBaseEngine::calculate(): empty discount curve for ccy" <<
baseCcy_);
172 QL_REQUIRE(!
defaultCurve_.empty(),
"RiskParticipationAgreementBaseEngine::calculate(): empty default curve");
174 "RiskParticipationAgreementBaseEngine::calculate(): empty recovery and trade does not specify "
190 std::vector<std::vector<Date>> feeStartDates;
191 std::vector<std::vector<Date>> feeEndDates;
192 std::vector<std::vector<Date>> feePayDates;
193 std::vector<std::vector<Date>> feeMidDates;
194 std::vector<std::vector<double>> feeAmounts;
195 std::vector<std::vector<double>> feeMidAccrueds;
196 std::vector<std::vector<double>> feeMidDiscounts;
197 std::vector<std::vector<double>> feeDiscounts;
198 std::vector<std::vector<double>> feeSurvivalProbs;
199 std::vector<std::vector<double>> feePeriodPDs;
200 std::vector<double> feeFXSpot;
201 for (
auto const& l :
arguments_.protectionFee) {
203 "RiskParticipationAgreementBaseEngine::calculate(): empty discount curve for ccy "
206 "RiskParticipationAgreementBaseEngine::calculate(): empty fx spot for ccy "
209 std::vector<Date> thisFeeStartDates;
210 std::vector<Date> thisFeeEndDates;
211 std::vector<Date> thisFeePayDates;
212 std::vector<Date> thisFeeMidDates;
213 std::vector<double> thisFeeAmounts;
214 std::vector<double> thisFeeMidAccrueds;
215 std::vector<double> thisFeeMidDiscounts;
216 std::vector<double> thisFeeDiscounts;
217 std::vector<double> thisFeeSurvivalProbs;
218 std::vector<double> thisFeePeriodPDs;
219 for (
auto const& c : l) {
222 thisFeePayDates.push_back(c->date());
223 thisFeeAmounts.push_back(c->amount());
225 thisFeeSurvivalProbs.push_back(
defaultCurve_->survivalProbability(c->date()));
227 fee += thisFeeAmounts.back() * thisFeeDiscounts.back() * feeFXSpot.back() * thisFeeSurvivalProbs.back();
229 auto cpn = QuantLib::ext::dynamic_pointer_cast<Coupon>(c);
232 Date end = cpn->accrualEndDate();
233 thisFeeStartDates.push_back(start);
234 thisFeeEndDates.push_back(end);
236 Date mid = start + (end - start) / 2;
237 thisFeeMidDates.push_back(mid);
238 thisFeeMidAccrueds.push_back(cpn->accruedAmount(mid));
240 thisFeePeriodPDs.push_back(
defaultCurve_->defaultProbability(start, end));
241 fee += thisFeeMidAccrueds.back() * thisFeeMidDiscounts.back() * feeFXSpot.back() *
242 thisFeePeriodPDs.back();
246 feeStartDates.push_back(thisFeeStartDates);
247 feeEndDates.push_back(thisFeeEndDates);
248 feePayDates.push_back(thisFeePayDates);
249 feeMidDates.push_back(thisFeeMidDates);
250 feeAmounts.push_back(thisFeeAmounts);
251 feeMidAccrueds.push_back(thisFeeMidAccrueds);
252 feeMidDiscounts.push_back(thisFeeMidDiscounts);
253 feeDiscounts.push_back(thisFeeDiscounts);
254 feeSurvivalProbs.push_back(thisFeeSurvivalProbs);
255 feePeriodPDs.push_back(thisFeePeriodPDs);
262 Real protection = 0.0;
275 std::vector<Real> gridPeriodPds;
276 for (Size i = 0; i <
gridDates_.size() - 1; ++i)
280 results_.additionalResults[
"ProtectionLegNpv"] = (
arguments_.protectionFeePayer ? 1.0 : -1.0) * protection;
281 results_.additionalResults[
"FeeLegNpv"] = (
arguments_.protectionFeePayer ? 1.0 : -1.0) * fee;
283 results_.additionalResults[
"GridPeriodPDs"] = gridPeriodPds;
286 for (Size l = 0; l <
arguments_.protectionFee.size(); ++l) {
287 results_.additionalResults[
"FeeStartDates"] = feeStartDates[l];
288 results_.additionalResults[
"FeeEndDates"] = feeEndDates[l];
289 results_.additionalResults[
"FeePayDates"] = feePayDates[l];
290 results_.additionalResults[
"FeeMidDates"] = feeMidDates[l];
291 results_.additionalResults[
"FeeAmounts"] = feeAmounts[l];
292 results_.additionalResults[
"FeeMidAccrueds"] = feeMidAccrueds[l];
293 results_.additionalResults[
"FeeMidDiscounts"] = feeMidDiscounts[l];
294 results_.additionalResults[
"FeeDiscounts"] = feeDiscounts[l];
295 results_.additionalResults[
"FeeSurvivalProbs"] = feeSurvivalProbs[l];
296 results_.additionalResults[
"FeePeriodPDs"] = feePeriodPDs[l];
297 results_.additionalResults[
"FeeFXSpot"] = feeFXSpot;
const Instrument::results * results_
static std::vector< Date > buildDiscretisationGrid(const Date &referenceDate, const Date &protectionStart, const Date &protectionEnd, const std::vector< Leg > &underlying, const Size maxGapDays=Null< Size >(), const Size maxDiscretisationPoints=Null< Size >())
Real effectiveRecoveryRate_
std::vector< Date > gridDates_
virtual Real protectionLegNpv() const =0
void calculate() const override
RiskParticipationAgreementBaseEngine(const std::string &baseCcy, const std::map< std::string, Handle< YieldTermStructure > > &discountCurves, const std::map< std::string, Handle< Quote > > &fxSpots, const Handle< DefaultProbabilityTermStructure > &defaultCurve, const Handle< Quote > &recoveryRate, const Size maxGapDays=Null< Size >(), const Size maxDiscretizsationPoints=Null< Size >())
std::map< std::string, Handle< Quote > > fxSpots_
std::map< std::string, Handle< YieldTermStructure > > discountCurves_
Handle< DefaultProbabilityTermStructure > defaultCurve_
Size maxDiscretisationPoints_
Handle< Quote > recoveryRate_
Serializable Credit Default Swap.
Swap::arguments * arguments_