Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Public Member Functions | Static Public Member Functions | Protected Member Functions | Protected Attributes | List of all members
RiskParticipationAgreementBaseEngine Class Referenceabstract

#include <ored/scripting/engines/riskparticipationagreementbaseengine.hpp>

+ Inheritance diagram for RiskParticipationAgreementBaseEngine:
+ Collaboration diagram for RiskParticipationAgreementBaseEngine:

Public Member Functions

 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 >())
 

Static Public Member Functions

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 >())
 

Protected Member Functions

virtual Real protectionLegNpv () const =0
 
void calculate () const override
 

Protected Attributes

std::string baseCcy_
 
std::map< std::string, Handle< YieldTermStructure > > discountCurves_
 
std::map< std::string, Handle< Quote > > fxSpots_
 
Handle< DefaultProbabilityTermStructure > defaultCurve_
 
Handle< Quote > recoveryRate_
 
Size maxGapDays_
 
Size maxDiscretisationPoints_
 
std::vector< Date > gridDates_
 
Date referenceDate_
 
Real effectiveRecoveryRate_
 

Detailed Description

Definition at line 35 of file riskparticipationagreementbaseengine.hpp.

Constructor & Destructor Documentation

◆ RiskParticipationAgreementBaseEngine()

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>() 
)

Definition at line 29 of file riskparticipationagreementbaseengine.cpp.

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");
37 QL_REQUIRE(maxDiscretisationPoints_ == Null<Size>() || maxDiscretisationPoints_ >= 1,
38 "invalid maxDiscretisationPoints (" << maxDiscretisationPoints << "), must be >= 3");
39 for (auto const& d : discountCurves_)
40 registerWith(d.second);
41 for (auto const& s : fxSpots_)
42 registerWith(s.second);
43 registerWith(defaultCurve_);
44 registerWith(recoveryRate_);
45 fxSpots_[baseCcy_] = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(1.0));
46}
std::map< std::string, Handle< YieldTermStructure > > discountCurves_

Member Function Documentation

◆ buildDiscretisationGrid()

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>() 
)
static

Definition at line 62 of file riskparticipationagreementbaseengine.cpp.

64 {
65
66 QL_REQUIRE(protectionEnd > referenceDate,
67 "protection end (" << protectionEnd << ") must be > reference date (" << referenceDate << ")");
68
69 // collect the accrual end dates of the float coupons
70
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());
76 }
77 }
78 }
79
80 // build the discretisation grid
81
82 accrualDates.push_back(std::max(protectionStart, referenceDate));
83 accrualDates.push_back(protectionEnd);
84
85 std::sort(accrualDates.begin(), accrualDates.end());
86 auto it = std::unique(accrualDates.begin(), accrualDates.end());
87 accrualDates.resize(it - accrualDates.begin());
88
89 auto itStart = std::lower_bound(accrualDates.begin(), accrualDates.end(), referenceDate);
90 auto itEnd = std::upper_bound(accrualDates.begin(), accrualDates.end(), protectionEnd);
91
92 QL_REQUIRE(std::distance(itStart, itEnd) >= 2, "got invalid discretisationGrid for RPA, this is unexpected");
93
94 std::vector<Date> gridDates(itStart, itEnd);
95
96 // add additional dates on mid points of intervals that are exceeding the max gap given
97
98 if (maxGapDays != Null<Size>()) {
99 bool refining;
100 // just to really make sure we exit the loop below!
101 Size refiningIterations = 0;
102 do {
103 refining = false;
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);
107 refining = true;
108 }
109 }
110 } while (refining && ++refiningIterations < 100);
111 QL_REQUIRE(refiningIterations < 100, "discretisationGrid refinement failed, this is unexpected");
112 }
113
114 // if the number of intervals exceeds the max allowed number, remove points at the beginning and end like this
115 //
116 // (1) | x | x | x | x | x | x | x | x | x | =>
117 // (2) | x | x | x | x | x | x | x | =>
118 // (3) | x | x | x | x | x | etc.
119 //
120 // where each '|' marks an entry in gridDates and 'x' marks the midpoint of the intervals,
121 // until we reach the max allowed number of discretisation points.
122
123 // just for debugging
124 // std::vector<Date> originalGridDates(gridDates);
125 // logGrid(originalGridDates, gridDates);
126
127 Size currentNumberOfDiscretisationPoints = gridDates.size() - 1,
128 previousNumberOfDiscretisationPoints = QL_MAX_INTEGER;
129
130 while (maxDiscretisationPoints != Null<Size>() && currentNumberOfDiscretisationPoints > maxDiscretisationPoints &&
131 currentNumberOfDiscretisationPoints < previousNumberOfDiscretisationPoints) {
132
133 previousNumberOfDiscretisationPoints = currentNumberOfDiscretisationPoints;
134 Size currentLeftIndex = 0, currentRightIndex = gridDates.size() - 1;
135 bool nextErasureOnLeft = true, canRemoveFurtherPointsInPass = true;
136
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;
144 currentLeftIndex++;
145 nextErasureOnLeft = false;
146 } else {
147 canRemoveFurtherPointsInPass = false;
148 }
149 } else {
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;
156 } else {
157 canRemoveFurtherPointsInPass = false;
158 }
159 }
160 // just for debugging
161 // logGrid(originalGridDates, gridDates);
162 }
163 }
164
165 return gridDates;
166}
Date referenceDate
Definition: utilities.cpp:442
+ Here is the caller graph for this function:

◆ protectionLegNpv()

virtual Real protectionLegNpv ( ) const
protectedpure virtual

Implemented in AnalyticBlackRiskParticipationAgreementEngine, AnalyticXCcyBlackRiskParticipationAgreementEngine, and NumericLgmRiskParticipationAgreementEngine.

+ Here is the caller graph for this function:

◆ calculate()

void calculate ( ) const
overrideprotected

Definition at line 168 of file riskparticipationagreementbaseengine.cpp.

168 {
169
170 QL_REQUIRE(!discountCurves_[baseCcy_].empty(),
171 "RiskParticipationAgreementBaseEngine::calculate(): empty discount curve for ccy" << baseCcy_);
172 QL_REQUIRE(!defaultCurve_.empty(), "RiskParticipationAgreementBaseEngine::calculate(): empty default curve");
173 QL_REQUIRE(arguments_.fixedRecoveryRate != Null<Real>() || !recoveryRate_.empty(),
174 "RiskParticipationAgreementBaseEngine::calculate(): empty recovery and trade does not specify "
175 "fixed recovery");
176
177 // asof date for valuation
178
179 referenceDate_ = discountCurves_[baseCcy_]->referenceDate();
180
181 // effective recovery rate to use
182
184 arguments_.fixedRecoveryRate == Null<Real>() ? recoveryRate_->value() : arguments_.fixedRecoveryRate;
185
186 // compute the fee leg NPV
187
188 Real fee = 0.0;
189 Size idx = 0;
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) {
202 QL_REQUIRE(!discountCurves_[arguments_.protectionFeeCcys[idx]].empty(),
203 "RiskParticipationAgreementBaseEngine::calculate(): empty discount curve for ccy "
204 << arguments_.protectionFeeCcys[idx]);
205 QL_REQUIRE(!fxSpots_[arguments_.protectionFeeCcys[idx]].empty(),
206 "RiskParticipationAgreementBaseEngine::calculate(): empty fx spot for ccy "
207 << arguments_.protectionFeeCcys[idx] + baseCcy_);
208 feeFXSpot.push_back(fxSpots_[arguments_.protectionFeeCcys[idx]]->value());
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) {
220 if (c->date() <= referenceDate_)
221 continue;
222 thisFeePayDates.push_back(c->date());
223 thisFeeAmounts.push_back(c->amount());
224 thisFeeDiscounts.push_back(discountCurves_[arguments_.protectionFeeCcys[idx]]->discount(c->date()));
225 thisFeeSurvivalProbs.push_back(defaultCurve_->survivalProbability(c->date()));
226 // the fee is only paid if the reference entity is still alive at the payment date
227 fee += thisFeeAmounts.back() * thisFeeDiscounts.back() * feeFXSpot.back() * thisFeeSurvivalProbs.back();
228 // accrual settlement using the mid of the coupon periods
229 auto cpn = QuantLib::ext::dynamic_pointer_cast<Coupon>(c);
230 if (cpn && arguments_.settlesAccrual) {
231 Date start = std::max(cpn->accrualStartDate(), referenceDate_);
232 Date end = cpn->accrualEndDate();
233 thisFeeStartDates.push_back(start);
234 thisFeeEndDates.push_back(end);
235 if (start < end) {
236 Date mid = start + (end - start) / 2;
237 thisFeeMidDates.push_back(mid);
238 thisFeeMidAccrueds.push_back(cpn->accruedAmount(mid));
239 thisFeeMidDiscounts.push_back(discountCurves_[arguments_.protectionFeeCcys[idx]]->discount(mid));
240 thisFeePeriodPDs.push_back(defaultCurve_->defaultProbability(start, end));
241 fee += thisFeeMidAccrueds.back() * thisFeeMidDiscounts.back() * feeFXSpot.back() *
242 thisFeePeriodPDs.back();
243 }
244 }
245 }
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);
256 ++idx;
257 }
258
259 // if we are past the protection end date, the protection leg NPV is zero, otherwise we call into the
260 // derived engine to compute this
261
262 Real protection = 0.0;
263 if (arguments_.protectionEnd > referenceDate_) {
266 protection = protectionLegNpv();
267 }
268
269 // compute the total NPV, we buy the protection if we pay the fee
270
271 results_.value = (arguments_.protectionFeePayer ? 1.0 : -1.0) * (protection - fee);
272
273 // set additional results
274
275 std::vector<Real> gridPeriodPds;
276 for (Size i = 0; i < gridDates_.size() - 1; ++i)
277 gridPeriodPds.push_back(defaultCurve_->defaultProbability(gridDates_[i], gridDates_[i + 1]));
278
279 results_.additionalResults["GridDates"] = gridDates_;
280 results_.additionalResults["ProtectionLegNpv"] = (arguments_.protectionFeePayer ? 1.0 : -1.0) * protection;
281 results_.additionalResults["FeeLegNpv"] = (arguments_.protectionFeePayer ? 1.0 : -1.0) * fee;
282 results_.additionalResults["RecoveryRate"] = effectiveRecoveryRate_;
283 results_.additionalResults["GridPeriodPDs"] = gridPeriodPds;
284 results_.additionalResults["ParticipationRate"] = arguments_.participationRate;
285
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;
298 results_.additionalResults["FeeCurrency"] = arguments_.protectionFeeCcys[l];
299 }
300}
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 >())
Swap::arguments * arguments_
+ Here is the call graph for this function:

Member Data Documentation

◆ baseCcy_

std::string baseCcy_
protected

Definition at line 54 of file riskparticipationagreementbaseengine.hpp.

◆ discountCurves_

std::map<std::string, Handle<YieldTermStructure> > discountCurves_
mutableprotected

Definition at line 55 of file riskparticipationagreementbaseengine.hpp.

◆ fxSpots_

std::map<std::string, Handle<Quote> > fxSpots_
mutableprotected

Definition at line 56 of file riskparticipationagreementbaseengine.hpp.

◆ defaultCurve_

Handle<DefaultProbabilityTermStructure> defaultCurve_
protected

Definition at line 57 of file riskparticipationagreementbaseengine.hpp.

◆ recoveryRate_

Handle<Quote> recoveryRate_
protected

Definition at line 58 of file riskparticipationagreementbaseengine.hpp.

◆ maxGapDays_

Size maxGapDays_
protected

Definition at line 59 of file riskparticipationagreementbaseengine.hpp.

◆ maxDiscretisationPoints_

Size maxDiscretisationPoints_
protected

Definition at line 59 of file riskparticipationagreementbaseengine.hpp.

◆ gridDates_

std::vector<Date> gridDates_
mutableprotected

Definition at line 62 of file riskparticipationagreementbaseengine.hpp.

◆ referenceDate_

Date referenceDate_
mutableprotected

Definition at line 63 of file riskparticipationagreementbaseengine.hpp.

◆ effectiveRecoveryRate_

Real effectiveRecoveryRate_
mutableprotected

Definition at line 64 of file riskparticipationagreementbaseengine.hpp.