Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
discountingswapenginemulticurve.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19#include <ql/cashflows/cashflows.hpp>
20#include <ql/cashflows/fixedratecoupon.hpp>
21#include <ql/cashflows/floatingratecoupon.hpp>
22#include <ql/cashflows/iborcoupon.hpp>
23#include <ql/cashflows/inflationcoupon.hpp>
24#include <ql/cashflows/simplecashflow.hpp>
25#include <ql/utilities/dataformatters.hpp>
26
28
29namespace QuantExt {
30
31namespace {
32
33class AmountGetter : public AcyclicVisitor,
34 public Visitor<CashFlow>,
35 public Visitor<Coupon>,
36 public Visitor<IborCoupon> {
37
38public:
39 AmountGetter() : amount_(0), callAmount_(true) {}
40 virtual ~AmountGetter() {}
41
42 Real amount() const { return amount_; }
43 virtual Real bpsFactor() const { return 0.0; }
44 void setCallAmount(bool flag) { callAmount_ = flag; }
45
46 void visit(CashFlow& c) override;
47 void visit(Coupon& c) override;
48 void visit(IborCoupon& c) override;
49
50private:
51 Real amount_;
53};
54
55void AmountGetter::visit(CashFlow& c) { amount_ = c.amount(); }
56
57void AmountGetter::visit(Coupon& c) { amount_ = c.amount(); }
58
59void AmountGetter::visit(IborCoupon& c) {
60 if (callAmount_) {
61 amount_ = c.amount();
62 } else {
63 Handle<YieldTermStructure> forwardingCurve = c.iborIndex()->forwardingTermStructure();
64 QL_REQUIRE(!forwardingCurve.empty(), "Forwarding curve is empty.");
65
66 /* Assuming here that Libor value/maturity date = coupon accrual start/end date */
67 DiscountFactor discAccStart = forwardingCurve->discount(c.accrualStartDate());
68 DiscountFactor discAccEnd = forwardingCurve->discount(c.accrualEndDate());
69
70 Real fixingTimesDcf;
71 DayCounter indexBasis = c.iborIndex()->dayCounter();
72 DayCounter couponBasis = c.dayCounter();
73 if (indexBasis == couponBasis) {
74 fixingTimesDcf = (discAccStart / discAccEnd - 1);
75 } else {
76 Time indexDcf = indexBasis.yearFraction(c.accrualStartDate(), c.accrualEndDate());
77 fixingTimesDcf = (discAccStart / discAccEnd - 1) / indexDcf * c.accrualPeriod();
78 }
79 amount_ = (c.gearing() * fixingTimesDcf + c.spread() * c.accrualPeriod()) * c.nominal();
80 }
81}
82
83class AdditionalAmountGetter : public AmountGetter {
84
85public:
86 AdditionalAmountGetter() {}
87 Real bpsFactor() const override { return bpsFactor_; }
88
89 void visit(CashFlow& c) override;
90 void visit(Coupon& c) override;
91 void visit(IborCoupon& c) override;
92
93private:
95};
96
97void AdditionalAmountGetter::visit(CashFlow& c) {
98 AmountGetter::visit(c);
99 bpsFactor_ = 0.0;
100}
101
102void AdditionalAmountGetter::visit(Coupon& c) {
103 AmountGetter::visit(c);
104 bpsFactor_ = c.accrualPeriod() * c.nominal();
105}
106
107void AdditionalAmountGetter::visit(IborCoupon& c) {
108 AmountGetter::visit(c);
109 bpsFactor_ = c.accrualPeriod() * c.nominal();
110}
111} // namespace
112
113class DiscountingSwapEngineMultiCurve::AmountImpl {
114public:
115 QuantLib::ext::shared_ptr<AmountGetter> amountGetter_;
116};
117
118DiscountingSwapEngineMultiCurve::DiscountingSwapEngineMultiCurve(const Handle<YieldTermStructure>& discountCurve,
119 bool minimalResults,
120 boost::optional<bool> includeSettlementDateFlows,
121 Date settlementDate, Date npvDate)
122 : discountCurve_(discountCurve), minimalResults_(minimalResults),
123 includeSettlementDateFlows_(includeSettlementDateFlows), settlementDate_(settlementDate), npvDate_(npvDate),
124 impl_(new AmountImpl) {
125
126 registerWith(discountCurve_);
127
128 if (minimalResults_) {
129 impl_->amountGetter_.reset(new AmountGetter);
130 } else {
131 impl_->amountGetter_.reset(new AdditionalAmountGetter);
132 }
133}
134
136 QL_REQUIRE(!discountCurve_.empty(), "Empty discounting "
137 "term structure handle");
138
139 // Instrument settlement date
140 Date referenceDate = discountCurve_->referenceDate();
141 Date settlementDate = settlementDate_;
142 if (settlementDate_ == Date()) {
143 settlementDate = referenceDate;
144 } else {
145 QL_REQUIRE(settlementDate >= referenceDate, "settlement date (" << settlementDate
146 << ") before "
147 "discount curve reference date ("
148 << referenceDate << ")");
149 }
150
151 // - Instrument::results
152 results_.value = 0.0;
153 results_.errorEstimate = Null<Real>();
154 results_.valuationDate = npvDate_;
155 if (npvDate_ == Date()) {
156 results_.valuationDate = referenceDate;
157 } else {
158 QL_REQUIRE(npvDate_ >= referenceDate, "npv date (" << npvDate_
159 << ") before "
160 "discount curve reference date ("
161 << referenceDate << ")");
162 }
163
164 // - Swap::results
165 Size numLegs = arguments_.legs.size();
166 results_.legNPV.resize(numLegs);
167 results_.legBPS.resize(numLegs);
168 results_.startDiscounts.resize(numLegs);
169 results_.endDiscounts.resize(numLegs);
170 results_.npvDateDiscount = discountCurve_->discount(results_.valuationDate);
171
172 bool includeRefDateFlows =
173 includeSettlementDateFlows_ ? *includeSettlementDateFlows_ : Settings::instance().includeReferenceDateEvents();
174
175 const Spread bp = 1.0e-4;
176
177 for (Size i = 0; i < numLegs; i++) {
178
179 Leg leg = arguments_.legs[i];
180 results_.legNPV[i] = 0.0;
181 results_.legBPS[i] = 0.0;
182
183 // Call amount() method of underlying coupon for first coupon.
184 impl_->amountGetter_->setCallAmount(true);
185
186 for (Size j = 0; j < leg.size(); j++) {
187
188 /* Exclude cashflows that have occurred taking into account the
189 settlement date and includeSettlementDateFlows flag */
190 if (leg[j]->hasOccurred(settlementDate, includeRefDateFlows)) {
191 continue;
192 }
193
194 DiscountFactor discount = discountCurve_->discount(leg[j]->date());
195 leg[j]->accept(*(impl_->amountGetter_));
196 results_.legNPV[i] += impl_->amountGetter_->amount() * discount;
197 results_.legBPS[i] += impl_->amountGetter_->bpsFactor() * discount;
198
199 // For all coupons after second do not call amount(), since for those
200 // we can be sure that they are not fixed yet
201 if (j == 1)
202 impl_->amountGetter_->setCallAmount(false);
203 }
204
205 results_.legNPV[i] *= arguments_.payer[i];
206 results_.legNPV[i] /= results_.npvDateDiscount;
207 results_.legBPS[i] *= arguments_.payer[i] * bp;
208 results_.legBPS[i] /= results_.npvDateDiscount;
209 results_.value += results_.legNPV[i];
210 }
211}
212} // namespace QuantExt
const Instrument::results * results_
Definition: cdsoption.cpp:81
DiscountingSwapEngineMultiCurve(const Handle< YieldTermStructure > &discountCurve=Handle< YieldTermStructure >(), bool minimalResults=true, boost::optional< bool > includeSettlementDateFlows=boost::none, Date settlementDate=Date(), Date npvDate=Date())
Swap engine employing assumptions to speed up calculation.
Swap::arguments * arguments_