QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.38
Loading...
Searching...
No Matches
assetswap.cpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2006, 2007 Chiara Fornarola
5 Copyright (C) 2007, 2009, 2011 Ferdinando Ametrano
6 Copyright (C) 2007, 2009 StatPro Italia srl
7
8 This file is part of QuantLib, a free-software/open-source library
9 for financial quantitative analysts and developers - http://quantlib.org/
10
11 QuantLib is free software: you can redistribute it and/or modify it
12 under the terms of the QuantLib license. You should have received a
13 copy of the license along with this program; if not, please email
14 <quantlib-dev@lists.sf.net>. The license is also available online at
15 <http://quantlib.org/license.shtml>.
16
17 This program is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 FOR A PARTICULAR PURPOSE. See the license for more details.
20*/
21
30#include <utility>
31
32using std::vector;
33
34namespace QuantLib {
35
37 ext::shared_ptr<Bond> bond,
38 Real bondCleanPrice,
39 Real nonParRepayment,
40 Real gearing,
41 const ext::shared_ptr<IborIndex>& iborIndex,
42 Spread spread,
43 const DayCounter& floatingDayCounter,
44 Date dealMaturity,
45 bool payBondCoupon)
46 : AssetSwap(payBondCoupon, std::move(bond), bondCleanPrice, iborIndex, spread,
47 Schedule(), floatingDayCounter, parSwap, gearing,
48 nonParRepayment, dealMaturity) {}
49
50 AssetSwap::AssetSwap(bool payBondCoupon,
51 ext::shared_ptr<Bond> bond,
52 Real bondCleanPrice,
53 const ext::shared_ptr<IborIndex>& iborIndex,
54 Spread spread,
55 Schedule floatSchedule,
56 const DayCounter& floatingDayCounter,
57 bool parSwap,
58 Real gearing,
59 Real nonParRepayment,
60 Date dealMaturity)
61 : Swap(2), bond_(std::move(bond)), bondCleanPrice_(bondCleanPrice),
62 nonParRepayment_(nonParRepayment), spread_(spread), parSwap_(parSwap) {
63
64 auto overnight = ext::dynamic_pointer_cast<OvernightIndex>(iborIndex);
65 if (overnight) {
66 QL_REQUIRE(!floatSchedule.empty(),
67 "floating schedule is needed when using an overnight index");
68 }
69
70 Schedule schedule = floatSchedule.empty()
71 ? Schedule(bond_->settlementDate(),
72 bond_->maturityDate(),
73 iborIndex->tenor(),
74 iborIndex->fixingCalendar(),
75 iborIndex->businessDayConvention(),
76 iborIndex->businessDayConvention(),
78 false) // endOfMonth
79 : std::move(floatSchedule);
80
81 if (dealMaturity == Date())
82 dealMaturity = schedule.back();
83 QL_REQUIRE(dealMaturity <= schedule.back(),
84 "deal maturity " << dealMaturity <<
85 " cannot be later than (adjusted) bond maturity " <<
86 schedule.back());
87 QL_REQUIRE(dealMaturity > schedule.front(),
88 "deal maturity " << dealMaturity <<
89 " must be later than swap start date " <<
90 schedule.front());
91
92 // the following might become an input parameter
93 BusinessDayConvention paymentAdjustment = Following;
94
95 Date finalDate = schedule.calendar().adjust(
96 dealMaturity, paymentAdjustment);
97 schedule = schedule.until(finalDate);
98
99 // bondCleanPrice must be the (forward) clean price
100 // at the floating schedule start date
101 upfrontDate_ = schedule.startDate();
102 Real dirtyPrice = bondCleanPrice_ + bond_->accruedAmount(upfrontDate_);
103
104 Real notional = bond_->notional(upfrontDate_);
105 /* In the market asset swap, the bond is purchased in return for
106 payment of the full price. The notional of the floating leg is
107 then scaled by the full price. */
108 if (!parSwap_)
109 notional *= dirtyPrice/100.0;
110
111 /******** Bond leg ********/
112
113 const Leg& bondLeg = bond_->cashflows();
114 QL_REQUIRE(!bondLeg.empty(), "no cashflows from bond");
115
116 bool includeOnUpfrontDate = false; // a cash flow on the upfront
117 // date must be discarded
118
119 // add coupons for the time being, not the redemption
120 Leg::const_iterator i;
121 for (i = bondLeg.begin(); i < bondLeg.end()-1 && (*i)->date()<=dealMaturity; ++i) {
122 if (!(*i)->hasOccurred(upfrontDate_, includeOnUpfrontDate))
123 legs_[0].push_back(*i);
124 }
125
126 // if we're skipping a cashflow before the redemption
127 // and it's a coupon, then add the accrued coupon.
128 if (i < bondLeg.end()-1) {
129 auto c = ext::dynamic_pointer_cast<Coupon>(*i);
130 if (c != nullptr) {
131 Real accruedAmount = c->accruedAmount(dealMaturity);
132 auto accruedCoupon =
133 ext::make_shared<SimpleCashFlow>(accruedAmount, finalDate);
134 legs_[0].push_back(accruedCoupon);
135 }
136 }
137
138 // add the redemption, or whatever the final payment is
139 if (nonParRepayment_ == Null<Real>()) {
140 auto redemption = bondLeg.back();
141 auto finalFlow =
142 ext::make_shared<SimpleCashFlow>(redemption->amount(), finalDate);
143 legs_[0].push_back(finalFlow);
144 nonParRepayment_ = 100.0;
145 } else {
146 auto finalFlow =
147 ext::make_shared<SimpleCashFlow>(nonParRepayment_, finalDate);
148 legs_[0].push_back(finalFlow);
149 }
150
151 /******** Floating leg ********/
152
153 if (overnight) {
154 legs_[1] =
155 OvernightLeg(std::move(schedule), overnight)
156 .withNotionals(notional)
157 .withPaymentAdjustment(paymentAdjustment)
158 .withGearings(gearing)
160 .withPaymentDayCounter(floatingDayCounter);
161 } else {
162 legs_[1] =
163 IborLeg(std::move(schedule), iborIndex)
164 .withNotionals(notional)
165 .withPaymentAdjustment(paymentAdjustment)
166 .withGearings(gearing)
168 .withPaymentDayCounter(floatingDayCounter);
169 }
170
171 if (parSwap_) {
172 // upfront
173 Real upfront = (dirtyPrice-100.0)/100.0 * notional;
174 auto upfrontCashFlow =
175 ext::make_shared<SimpleCashFlow>(upfront, upfrontDate_);
176 legs_[1].insert(legs_[1].begin(), upfrontCashFlow);
177 // backpayment (accounts for non-par redemption, if any)
178 Real backPayment = notional;
179 auto backPaymentCashFlow =
180 ext::make_shared<SimpleCashFlow>(backPayment, finalDate);
181 legs_[1].push_back(backPaymentCashFlow);
182 } else {
183 // final notional exchange
184 auto finalCashFlow =
185 ext::make_shared<SimpleCashFlow>(notional, finalDate);
186 legs_[1].push_back(finalCashFlow);
187 }
188
189 /******** registration and sides ********/
190
191 for (const auto& leg: legs_)
192 for (const auto& c: leg)
193 registerWith(c);
194
195 if (payBondCoupon) {
196 payer_[0]=-1.0;
197 payer_[1]=+1.0;
198 } else {
199 payer_[0]=+1.0;
200 payer_[1]=-1.0;
201 }
202 }
203
205
207
208 auto* arguments = dynamic_cast<AssetSwap::arguments*>(args);
209
210 if (arguments == nullptr) // it's a swap engine...
211 return;
212
213 const Leg& fixedCoupons = bondLeg();
214
216 vector<Date>(fixedCoupons.size());
217 arguments->fixedCoupons = vector<Real>(fixedCoupons.size());
218
219 for (Size i=0; i<fixedCoupons.size(); ++i) {
220 ext::shared_ptr<FixedRateCoupon> coupon =
221 ext::dynamic_pointer_cast<FixedRateCoupon>(fixedCoupons[i]);
222
223 arguments->fixedPayDates[i] = coupon->date();
224 arguments->fixedResetDates[i] = coupon->accrualStartDate();
225 arguments->fixedCoupons[i] = coupon->amount();
226 }
227
228 const Leg& floatingCoupons = floatingLeg();
229
232 vector<Date>(floatingCoupons.size());
234 vector<Time>(floatingCoupons.size());
236 vector<Spread>(floatingCoupons.size());
237
238 for (Size i=0; i<floatingCoupons.size(); ++i) {
239 ext::shared_ptr<FloatingRateCoupon> coupon =
240 ext::dynamic_pointer_cast<FloatingRateCoupon>(floatingCoupons[i]);
241
242 arguments->floatingResetDates[i] = coupon->accrualStartDate();
243 arguments->floatingPayDates[i] = coupon->date();
244 arguments->floatingFixingDates[i] = coupon->fixingDate();
245 arguments->floatingAccrualTimes[i] = coupon->accrualPeriod();
246 arguments->floatingSpreads[i] = coupon->spread();
247 }
248 }
249
251 static const Spread basisPoint = 1.0e-4;
252 calculate();
253 if (fairSpread_ != Null<Spread>()) {
254 return fairSpread_;
255 } else if (legBPS_.size() > 1 && legBPS_[1] != Null<Spread>()) {
256 fairSpread_ = spread_ - NPV_/legBPS_[1]*basisPoint;
257 return fairSpread_;
258 } else {
259 QL_FAIL("fair spread not available");
260 }
261 }
262
264 calculate();
265 QL_REQUIRE(legBPS_.size() > 1 && legBPS_[1] != Null<Real>(),
266 "floating-leg BPS not available");
267 return legBPS_[1];
268 }
269
271 calculate();
272 QL_REQUIRE(legNPV_.size() > 1 && legNPV_[1] != Null<Real>(),
273 "floating-leg NPV not available");
274 return legNPV_[1];
275 }
276
278 calculate();
279 if (fairCleanPrice_ != Null<Real>()) {
280 return fairCleanPrice_;
281 } else {
283 "fair clean price not available for seasoned deal");
284 Real notional = bond_->notional(upfrontDate_);
285 if (parSwap_) {
287 NPV_*npvDateDiscount_/startDiscounts_[1]/(notional/100.0);
288 } else {
289 Real accruedAmount = bond_->accruedAmount(upfrontDate_);
290 Real dirtyPrice = bondCleanPrice_ + accruedAmount;
291 Real fairDirtyPrice = - legNPV_[0]/legNPV_[1] * dirtyPrice;
292 fairCleanPrice_ = fairDirtyPrice - accruedAmount;
293 }
294
295 return fairCleanPrice_;
296 }
297 }
298
300 calculate();
303 } else {
305 "fair non par repayment not available for expired leg");
306 Real notional = bond_->notional(upfrontDate_);
308 NPV_*npvDateDiscount_/endDiscounts_[1]/(notional/100.0);
310 }
311 }
312
318 }
319
322 const auto* results = dynamic_cast<const AssetSwap::results*>(r);
323 if (results != nullptr) {
327 } else {
331 }
332 }
333
336 "number of fixed start dates different from "
337 "number of fixed payment dates");
338 QL_REQUIRE(fixedPayDates.size() == fixedCoupons.size(),
339 "number of fixed payment dates different from "
340 "number of fixed coupon amounts");
342 "number of floating start dates different from "
343 "number of floating payment dates");
345 "number of floating fixing dates different from "
346 "number of floating payment dates");
348 "number of floating accrual times different from "
349 "number of floating payment dates");
351 "number of floating spreads different from "
352 "number of floating payment dates");
353 }
354
360 }
361
362}
Bullet bond vs Libor swap.
Cash flow vector builders.
Arguments for asset swap calculation
Definition: assetswap.hpp:121
std::vector< Date > floatingResetDates
Definition: assetswap.hpp:128
std::vector< Spread > floatingSpreads
Definition: assetswap.hpp:131
std::vector< Date > floatingFixingDates
Definition: assetswap.hpp:129
std::vector< Date > fixedPayDates
Definition: assetswap.hpp:125
std::vector< Date > fixedResetDates
Definition: assetswap.hpp:124
void validate() const override
Definition: assetswap.cpp:334
std::vector< Time > floatingAccrualTimes
Definition: assetswap.hpp:127
std::vector< Real > fixedCoupons
Definition: assetswap.hpp:126
std::vector< Date > floatingPayDates
Definition: assetswap.hpp:130
Results from simple swap calculation
Definition: assetswap.hpp:136
Bullet bond vs Libor swap.
Definition: assetswap.hpp:51
Real fairCleanPrice() const
Definition: assetswap.cpp:277
const Leg & floatingLeg() const
Definition: assetswap.hpp:102
Spread fairSpread() const
Definition: assetswap.cpp:250
AssetSwap(bool payBondCoupon, ext::shared_ptr< Bond > bond, Real bondCleanPrice, const ext::shared_ptr< IborIndex > &iborIndex, Spread spread, Schedule floatSchedule=Schedule(), const DayCounter &floatingDayCount=DayCounter(), bool parAssetSwap=true, Real gearing=1.0, Real nonParRepayment=Null< Real >(), Date dealMaturity=Date())
Definition: assetswap.cpp:50
Real floatingLegBPS() const
Definition: assetswap.cpp:263
Real fairNonParRepayment() const
Definition: assetswap.cpp:299
void setupArguments(PricingEngine::arguments *args) const override
Definition: assetswap.cpp:204
const Leg & bondLeg() const
Definition: assetswap.hpp:101
ext::shared_ptr< Bond > bond_
Definition: assetswap.hpp:109
void setupExpired() const override
Definition: assetswap.cpp:313
Real floatingLegNPV() const
Definition: assetswap.cpp:270
void fetchResults(const PricingEngine::results *) const override
Definition: assetswap.cpp:320
Spread spread() const
Definition: assetswap.hpp:96
bool payBondCoupon() const
Definition: assetswap.hpp:100
Date adjust(const Date &, BusinessDayConvention convention=Following) const
Definition: calendar.cpp:84
Concrete date class.
Definition: date.hpp:125
day counter class
Definition: daycounter.hpp:44
helper class building a sequence of capped/floored ibor-rate coupons
Definition: iborcoupon.hpp:135
IborLeg & withSpreads(Spread spread)
Definition: iborcoupon.cpp:209
IborLeg & withPaymentAdjustment(BusinessDayConvention)
Definition: iborcoupon.cpp:174
IborLeg & withPaymentDayCounter(const DayCounter &)
Definition: iborcoupon.cpp:169
IborLeg & withNotionals(Real notional)
Definition: iborcoupon.cpp:159
IborLeg & withGearings(Real gearing)
Definition: iborcoupon.cpp:199
void calculate() const override
Definition: instrument.hpp:129
template class providing a null value for a given type.
Definition: null.hpp:59
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:226
helper class building a sequence of overnight coupons
OvernightLeg & withGearings(Real gearing)
OvernightLeg & withPaymentAdjustment(BusinessDayConvention)
OvernightLeg & withNotionals(Real notional)
OvernightLeg & withPaymentDayCounter(const DayCounter &)
OvernightLeg & withSpreads(Spread spread)
Payment schedule.
Definition: schedule.hpp:40
const Date & front() const
Definition: schedule.hpp:178
const Calendar & calendar() const
Definition: schedule.hpp:188
bool empty() const
Definition: schedule.hpp:74
const Date & startDate() const
Definition: schedule.hpp:192
const Date & back() const
Definition: schedule.hpp:183
Schedule until(const Date &truncationDate) const
Definition: schedule.cpp:454
void reset() override
Definition: swap.cpp:176
Interest rate swap.
Definition: swap.hpp:41
DiscountFactor npvDateDiscount_
Definition: swap.hpp:138
void setupArguments(PricingEngine::arguments *) const override
Definition: swap.cpp:87
std::vector< Leg > legs_
Definition: swap.hpp:133
std::vector< Real > legNPV_
Definition: swap.hpp:135
const Leg & leg(Size j) const
Definition: swap.hpp:111
std::vector< Real > legBPS_
Definition: swap.hpp:136
std::vector< DiscountFactor > startDiscounts_
Definition: swap.hpp:137
void setupExpired() const override
Definition: swap.cpp:78
void fetchResults(const PricingEngine::results *) const override
Definition: swap.cpp:95
std::vector< DiscountFactor > endDiscounts_
Definition: swap.hpp:137
std::vector< Real > payer_
Definition: swap.hpp:134
Coupon pricers.
discounting swap engine
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Definition: errors.hpp:92
Coupon paying a fixed annual rate.
BusinessDayConvention
Business Day conventions.
QL_REAL Real
real number
Definition: types.hpp:50
Real Spread
spreads on interest rates
Definition: types.hpp:74
std::size_t Size
size of a container
Definition: types.hpp:58
Coupon paying a Libor-type index.
Definition: any.hpp:37
std::vector< ext::shared_ptr< CashFlow > > Leg
Sequence of cash-flows.
Definition: cashflow.hpp:78
STL namespace.
coupon paying the compounded daily overnight rate
ext::shared_ptr< YieldTermStructure > r
Predetermined cash flow.