Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
equitymargincoupon.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2021 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
21
22#include <ql/utilities/vectors.hpp>
23
24using namespace QuantLib;
25
26namespace QuantExt {
27
28EquityMarginCoupon::EquityMarginCoupon(const Date& paymentDate, Real nominal, Rate rate, Real marginFactor, const Date& startDate, const Date& endDate,
29 Natural fixingDays, const QuantLib::ext::shared_ptr<EquityIndex2>& equityCurve,
30 const DayCounter& dayCounter, bool isTotalReturn, Real dividendFactor, bool notionalReset,
31 Real initialPrice, Real quantity, const Date& fixingStartDate, const Date& fixingEndDate,
32 const Date& refPeriodStart, const Date& refPeriodEnd, const Date& exCouponDate, Real multiplier,
33 const QuantLib::ext::shared_ptr<FxIndex>& fxIndex, const bool initialPriceIsInTargetCcy)
34 : Coupon(paymentDate, nominal, startDate, endDate, refPeriodStart, refPeriodEnd, exCouponDate),
35 fixingDays_(fixingDays), equityCurve_(equityCurve), dayCounter_(dayCounter), isTotalReturn_(isTotalReturn),
36 dividendFactor_(dividendFactor), notionalReset_(notionalReset), initialPrice_(initialPrice),
37 initialPriceIsInTargetCcy_(initialPriceIsInTargetCcy), quantity_(quantity), fixingStartDate_(fixingStartDate),
38 fixingEndDate_(fixingEndDate), fxIndex_(fxIndex), marginFactor_(marginFactor),
39 fixedRate_(InterestRate(rate, dayCounter, Simple, Annual)), multiplier_(multiplier) {
40
41 QL_REQUIRE(dividendFactor_ > 0.0, "Dividend factor should not be negative. It is expected to be between 0 and 1.");
42 QL_REQUIRE(equityCurve_, "Equity underlying an equity swap coupon cannot be empty.");
43
44 // If a fixing start / end date is provided, use these
45 // else adjust the start/endDate by the FixingDays - defaulted to 0
46 if (fixingStartDate_ == Date())
48 equityCurve_->fixingCalendar().advance(startDate, -static_cast<Integer>(fixingDays_), Days, Preceding);
49
50 if (fixingEndDate_ == Date())
52 equityCurve_->fixingCalendar().advance(endDate, -static_cast<Integer>(fixingDays_), Days, Preceding);
53
54 registerWith(equityCurve_);
55 registerWith(fxIndex_);
56 registerWith(Settings::instance().evaluationDate());
57
58 QL_REQUIRE(!notionalReset_ || quantity_ != Null<Real>(), "EquityCoupon: quantity required if notional resets");
59 QL_REQUIRE(notionalReset_ || nominal_ != Null<Real>(),
60 "EquityCoupon: notional required if notional does not reset");
61
62}
63
64void EquityMarginCoupon::setPricer(const QuantLib::ext::shared_ptr<EquityMarginCouponPricer>& pricer) {
65 if (pricer_)
66 unregisterWith(pricer_);
68 if (pricer_)
69 registerWith(pricer_);
70 update();
71}
72
74 if (notionalReset_) {
75 Real mult = (initialPrice_ == 0) ? 1 : initialPrice();
76 return mult * (initialPriceIsInTargetCcy_ ? 1.0 : fxRate()) * quantity_;
77 } else {
78 return nominal_;
79 }
80}
81
83 // fxRate applied if equity underlying currency differs from leg
84 return fxIndex_ ? fxIndex_->fixing(fixingStartDate_) : 1.0;
85}
86
88 if (initialPrice_ != Null<Real>())
89 return initialPrice_;
90 else
91 return equityCurve_->fixing(fixingStartDate(), false, false);
92}
93
95
96Real EquityMarginCoupon::accruedAmount(const Date& d) const {
97 if (d <= accrualStartDate_ || d > paymentDate_) {
98 return 0.0;
99 } else {
100 Time fullPeriod = dayCounter().yearFraction(accrualStartDate_, accrualEndDate_, refPeriodStart_, refPeriodEnd_);
101 Time thisPeriod =
102 dayCounter().yearFraction(accrualStartDate_, std::min(d, accrualEndDate_), refPeriodStart_, refPeriodEnd_);
103 return nominal() * rate() * thisPeriod / fullPeriod;
104 }
105}
106
107std::vector<Date> EquityMarginCoupon::fixingDates() const {
108 std::vector<Date> fixingDates;
109
110 fixingDates.push_back(fixingStartDate_);
111 fixingDates.push_back(fixingEndDate_);
112
113 return fixingDates;
114};
115
117 return rate() * nominal() * multiplier();
118}
119
121 QL_REQUIRE(pricer_, "pricer not set");
122 pricer_->initialize(*this);
123 return pricer_->rate();
124}
125
126EquityMarginLeg::EquityMarginLeg(const Schedule& schedule, const QuantLib::ext::shared_ptr<EquityIndex2>& equityCurve,
127 const QuantLib::ext::shared_ptr<FxIndex>& fxIndex)
128 : schedule_(schedule), equityCurve_(equityCurve), fxIndex_(fxIndex) {}
129
131 const DayCounter& dc,
132 Compounding comp,
133 Frequency freq) {
134 couponRates_.resize(1);
135 couponRates_[0] = InterestRate(rate, dc, comp, freq);
136 return *this;
137}
138
140 couponRates_.resize(1);
141 couponRates_[0] = i;
142 return *this;
143}
144
145EquityMarginLeg& EquityMarginLeg::withCouponRates(const std::vector<Rate>& rates,
146 const DayCounter& dc,
147 Compounding comp,
148 Frequency freq) {
149 couponRates_.resize(rates.size());
150 for (Size i=0; i<rates.size(); ++i)
151 couponRates_[i] = InterestRate(rates[i], dc, comp, freq);
152 return *this;
153}
154
156 const std::vector<InterestRate>& interestRates) {
157 couponRates_ = interestRates;
158 return *this;
159}
160
162 marginFactor_ = i;
163 return *this;
164}
165
167 notionals_ = std::vector<Real>(1, notional);
168 return *this;
169}
170
171EquityMarginLeg& EquityMarginLeg::withNotionals(const std::vector<Real>& notionals) {
172 notionals_ = notionals;
173 return *this;
174}
175
177 paymentDayCounter_ = dayCounter;
178 return *this;
179}
180
181EquityMarginLeg& EquityMarginLeg::withPaymentAdjustment(BusinessDayConvention convention) {
182 paymentAdjustment_ = convention;
183 return *this;
184}
185
187 paymentLag_ = paymentLag;
188 return *this;
189}
190
192 paymentCalendar_ = calendar;
193 return *this;
194}
195
197 isTotalReturn_ = totalReturn;
198 return *this;
199}
200
202 dividendFactor_ = dividendFactor;
203 return *this;
204}
205
207 initialPrice_ = initialPrice;
208 return *this;
209}
210
212 multiplier_ = multiplier;
213 return *this;
214}
215
217 initialPriceIsInTargetCcy_ = initialPriceIsInTargetCcy;
218 return *this;
219}
220
222 fixingDays_ = fixingDays;
223 return *this;
224}
225
226EquityMarginLeg& EquityMarginLeg::withValuationSchedule(const Schedule& valuationSchedule) {
227 valuationSchedule_ = valuationSchedule;
228 return *this;
229}
230
232 notionalReset_ = notionalReset;
233 return *this;
234}
235
237 quantity_ = quantity;
238 return *this;
239}
240
241EquityMarginLeg::operator Leg() const {
242
243 Leg cashflows;
244 Date startDate;
245 Date endDate;
246 Date paymentDate;
247 InterestRate rate = couponRates_[0];
248
249 Calendar calendar;
250 if (!paymentCalendar_.empty()) {
251 calendar = paymentCalendar_;
252 } else {
253 calendar = schedule_.calendar();
254 }
255
256 Size numPeriods = schedule_.size() - 1;
257
258 if (valuationSchedule_.size() > 0) {
259 QL_REQUIRE(valuationSchedule_.size() == schedule_.size(),
260 "mismatch in valuationSchedule (" << valuationSchedule_.size() << ") and scheduleData (" << schedule_.size() << ") sizes");
261 }
262
263 for (Size i = 0; i < numPeriods; ++i) {
264 startDate = schedule_.date(i);
265 endDate = schedule_.date(i + 1);
266 paymentDate = calendar.advance(endDate, paymentLag_, Days, paymentAdjustment_);
267
268 Date fixingStartDate = Date();
269 Date fixingEndDate = Date();
270 if (valuationSchedule_.size() > 0) {
271 fixingStartDate = valuationSchedule_.date(i);
272 fixingEndDate = valuationSchedule_.date(i + 1);
273 }
274
275 InterestRate rate;
276 if ((i-1) < couponRates_.size())
277 rate = couponRates_[i-1];
278 else
279 rate = couponRates_.back();
280
281 Real initialPrice = (i == 0) ? initialPrice_ : Null<Real>();
282 bool initialPriceIsInTargetCcy = initialPrice != Null<Real>() ? initialPriceIsInTargetCcy_ : false;
283 Real quantity = Null<Real>(), notional = Null<Real>();
284 if (notionalReset_) {
285 if (quantity_ != Null<Real>()) {
286 quantity = quantity_;
287 QL_REQUIRE(notionals_.empty(), "EquityMarginLeg: notional and quantity are given at the same time");
288 } else {
289 QL_REQUIRE(fxIndex_ == nullptr,
290 "EquityMarginLeg: can not compute quantity from nominal when fx conversion is required");
291 QL_REQUIRE(!notionals_.empty(), "EquityMarginLeg: can not compute qunantity, since no notional is given");
292 quantity = notionals_.front() ;
293 }
294 } else {
295 if (!notionals_.empty()) {
296 notional = detail::get(notionals_, i, 0.0);
297 QL_REQUIRE(quantity_ == Null<Real>(), "EquityMarginLeg: notional and quantity are given at the same time");
298 } else {
299 QL_REQUIRE(fxIndex_ == nullptr,
300 "EquityMarginLeg: can not compute notional from quantity when fx conversion is required");
301 QL_REQUIRE(quantity_ != Null<Real>(),
302 "EquityMarginLeg: can not compute notional, since no quantity is given");
303 notional = quantity_;
304 }
305 }
306
307 QuantLib::ext::shared_ptr<EquityMarginCoupon> cashflow(
308 new EquityMarginCoupon(paymentDate, notional, rate, marginFactor_, startDate, endDate, fixingDays_, equityCurve_, paymentDayCounter_,
309 isTotalReturn_, dividendFactor_, notionalReset_, initialPrice, quantity, fixingStartDate,
310 fixingEndDate, Date(), Date(), Date(), multiplier_, fxIndex_, initialPriceIsInTargetCcy));
311
312 QuantLib::ext::shared_ptr<EquityMarginCouponPricer> pricer(new EquityMarginCouponPricer);
313 cashflow->setPricer(pricer);
314
315 cashflows.push_back(cashflow);
316 }
317 return cashflows;
318}
319
320} // namespace QuantExt
QuantLib::ext::shared_ptr< QuantExt::EquityIndex2 > equityCurve_
QuantLib::ext::shared_ptr< FxIndex > fxIndex_
std::vector< Date > fixingDates() const
return both fixing dates
void setPricer(const QuantLib::ext::shared_ptr< EquityMarginCouponPricer > &)
bool initialPriceIsInTargetCcy() const
initial price is in target ccy (if applicable, i.e. if fxIndex != null, otherwise ignored)
Real fxRate() const
FX conversion rate (or 1.0 if not applicable)
DayCounter dayCounter() const override
Real accruedAmount(const Date &) const override
QuantLib::ext::shared_ptr< EquityMarginCouponPricer > pricer_
QuantLib::ext::shared_ptr< EquityMarginCouponPricer > pricer() const
EquityMarginCoupon(const Date &paymentDate, Real nominal, Rate rate, Real marginFactor, const Date &startDate, const Date &endDate, Natural fixingDays, const QuantLib::ext::shared_ptr< QuantExt::EquityIndex2 > &equityCurve, const DayCounter &dayCounter, bool isTotalReturn=false, Real dividendFactor=1.0, bool notionalReset=false, Real initialPrice=Null< Real >(), Real quantity=Null< Real >(), const Date &fixingStartDate=Date(), const Date &fixingEndDate=Date(), const Date &refPeriodStart=Date(), const Date &refPeriodEnd=Date(), const Date &exCouponDate=Date(), Real multiplier=Null< Real >(), const QuantLib::ext::shared_ptr< FxIndex > &fxIndex=nullptr, const bool initialPriceIsInTargetCcy=false)
Date fixingStartDate() const
The date at which the starting equity price is fixed.
Real initialPrice() const
initial price
Pricer for equity margin coupons.
helper class building a sequence of equity margin coupons
EquityMarginLeg & withPaymentCalendar(const Calendar &calendar)
EquityMarginLeg & withPaymentLag(Natural paymentLag)
EquityMarginLeg & withQuantity(Real)
BusinessDayConvention paymentAdjustment_
EquityMarginLeg & withNotionalReset(bool)
EquityMarginLeg & withNotionals(const std::vector< Real > &notionals)
EquityMarginLeg & withFixingDays(Natural)
std::vector< InterestRate > couponRates_
EquityMarginLeg & withDividendFactor(Real)
EquityMarginLeg(const Schedule &schedule, const QuantLib::ext::shared_ptr< QuantExt::EquityIndex2 > &equityCurve, const QuantLib::ext::shared_ptr< FxIndex > &fxIndex=nullptr)
EquityMarginLeg & withInitialPrice(Real)
std::vector< Real > notionals_
EquityMarginLeg & withNotional(Real notional)
EquityMarginLeg & withInitialPriceIsInTargetCcy(bool)
EquityMarginLeg & withPaymentAdjustment(BusinessDayConvention convention)
EquityMarginLeg & withTotalReturn(bool)
EquityMarginLeg & withPaymentDayCounter(const DayCounter &dayCounter)
EquityMarginLeg & withMultiplier(Real)
EquityMarginLeg & withValuationSchedule(const Schedule &valuationSchedule)
EquityMarginLeg & withInitialMarginFactor(const Real &marginFactor)
EquityMarginLeg & withCouponRates(Rate, const DayCounter &paymentDayCounter, Compounding comp=Simple, Frequency freq=Annual)
coupon paying the return on an equity
Pricer for equity margin coupons.