/src/quantlib/ql/experimental/basismodels/swaptioncfs.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* |
4 | | Copyright (C) 2018 Sebastian Schlenkrich |
5 | | |
6 | | This file is part of QuantLib, a free-software/open-source library |
7 | | for financial quantitative analysts and developers - http://quantlib.org/ |
8 | | |
9 | | QuantLib is free software: you can redistribute it and/or modify it |
10 | | under the terms of the QuantLib license. You should have received a |
11 | | copy of the license along with this program; if not, please email |
12 | | <quantlib-dev@lists.sf.net>. The license is also available online at |
13 | | <https://www.quantlib.org/license.shtml>. |
14 | | |
15 | | This program is distributed in the hope that it will be useful, but WITHOUT |
16 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
17 | | FOR A PARTICULAR PURPOSE. See the license for more details. |
18 | | */ |
19 | | |
20 | | /*! \file swaptioncfs.cpp |
21 | | \brief translate swaption into deterministic fixed and float cash flows |
22 | | */ |
23 | | |
24 | | #include <ql/experimental/basismodels/swaptioncfs.hpp> |
25 | | #include <ql/cashflows/coupon.hpp> |
26 | | #include <ql/cashflows/fixedratecoupon.hpp> |
27 | | #include <ql/cashflows/simplecashflow.hpp> |
28 | | #include <ql/exercise.hpp> |
29 | | #include <ql/settings.hpp> |
30 | | |
31 | | |
32 | | namespace QuantLib { |
33 | | |
34 | | IborLegCashFlows::IborLegCashFlows(const Leg& iborLeg, |
35 | | const Handle<YieldTermStructure>& discountCurve, |
36 | | bool contTenorSpread) |
37 | 0 | : refDate_(discountCurve->referenceDate()) { |
38 | | // we need to find the first coupon for initial payment |
39 | 0 | Size floatIdx = 0; |
40 | 0 | while ( |
41 | 0 | (floatIdx + 1 < iborLeg.size()) && |
42 | 0 | (refDate_ > (ext::dynamic_pointer_cast<Coupon>(iborLeg[floatIdx]))->accrualStartDate())) |
43 | 0 | ++floatIdx; |
44 | 0 | if (refDate_ <= (ext::dynamic_pointer_cast<Coupon>(iborLeg[floatIdx])) |
45 | 0 | ->accrualStartDate()) { // otherwise there is no floating coupon left |
46 | 0 | ext::shared_ptr<Coupon> firstFloatCoupon = |
47 | 0 | ext::dynamic_pointer_cast<Coupon>(iborLeg[floatIdx]); |
48 | 0 | floatLeg_.push_back(ext::shared_ptr<CashFlow>(new SimpleCashFlow( |
49 | 0 | firstFloatCoupon->nominal(), firstFloatCoupon->accrualStartDate()))); |
50 | | // calculate spread payments |
51 | 0 | for (Size k = floatIdx; k < iborLeg.size(); ++k) { |
52 | 0 | ext::shared_ptr<Coupon> coupon = ext::dynamic_pointer_cast<Coupon>(iborLeg[k]); |
53 | 0 | if (!coupon) |
54 | 0 | QL_FAIL("FloatingLeg CashFlow is no Coupon."); |
55 | 0 | Date startDate = coupon->accrualStartDate(); |
56 | 0 | Date endDate = coupon->accrualEndDate(); |
57 | 0 | Rate liborForwardRate = coupon->rate(); |
58 | 0 | Rate discForwardRate = |
59 | 0 | (discountCurve->discount(startDate) / discountCurve->discount(endDate) - 1.0) / |
60 | 0 | coupon->accrualPeriod(); |
61 | 0 | Rate spread; |
62 | 0 | Date payDate; |
63 | 0 | if (contTenorSpread) { |
64 | | // Db = (1 + Delta L^libor) / (1 + Delta L^ois) |
65 | | // spread (Db - 1) paid at startDate |
66 | 0 | spread = ((1.0 + coupon->accrualPeriod() * liborForwardRate) / |
67 | 0 | (1.0 + coupon->accrualPeriod() * discForwardRate) - |
68 | 0 | 1.0) / |
69 | 0 | coupon->accrualPeriod(); |
70 | 0 | payDate = startDate; |
71 | 0 | } else { |
72 | | // spread L^libor - L^ois |
73 | 0 | spread = liborForwardRate - discForwardRate; |
74 | 0 | payDate = coupon->date(); |
75 | 0 | } |
76 | 0 | floatLeg_.push_back(ext::shared_ptr<CashFlow>(new FixedRateCoupon( |
77 | 0 | payDate, coupon->nominal(), spread, coupon->dayCounter(), startDate, endDate))); |
78 | 0 | } // for ... |
79 | | // finally, add the notional at the last date |
80 | 0 | ext::shared_ptr<Coupon> lastFloatCoupon = |
81 | 0 | ext::dynamic_pointer_cast<Coupon>(iborLeg.back()); |
82 | 0 | floatLeg_.push_back(ext::shared_ptr<CashFlow>(new SimpleCashFlow( |
83 | 0 | -1.0 * lastFloatCoupon->nominal(), lastFloatCoupon->accrualEndDate()))); |
84 | 0 | } // if ... |
85 | | // assemble raw cash flow data... |
86 | 0 | Actual365Fixed dc; |
87 | | // ... float times/weights |
88 | 0 | for (auto& k : floatLeg_) |
89 | 0 | floatTimes_.push_back(dc.yearFraction(refDate_, k->date())); |
90 | 0 | for (auto& k : floatLeg_) |
91 | 0 | floatWeights_.push_back(k->amount()); |
92 | 0 | } |
93 | | |
94 | | SwapCashFlows::SwapCashFlows(const ext::shared_ptr<FixedVsFloatingSwap>& swap, |
95 | | const Handle<YieldTermStructure>& discountCurve, |
96 | | bool contTenorSpread) |
97 | 0 | : IborLegCashFlows(swap->floatingLeg(), discountCurve, contTenorSpread) { |
98 | | // copy fixed leg coupons |
99 | 0 | Leg fixedLeg = swap->fixedLeg(); |
100 | 0 | for (auto& k : fixedLeg) { |
101 | 0 | if (ext::dynamic_pointer_cast<Coupon>(k)->accrualStartDate() >= refDate_) |
102 | 0 | fixedLeg_.push_back(k); |
103 | 0 | } |
104 | 0 | Actual365Fixed dc; |
105 | | // ... fixed times/weights |
106 | 0 | for (auto& k : fixedLeg_) |
107 | 0 | fixedTimes_.push_back(dc.yearFraction(refDate_, k->date())); |
108 | 0 | for (auto& k : fixedLeg_) |
109 | 0 | fixedWeights_.push_back(k->amount()); |
110 | 0 | for (auto& k : fixedLeg_) { |
111 | 0 | ext::shared_ptr<Coupon> coupon = ext::dynamic_pointer_cast<Coupon>(k); |
112 | 0 | if (coupon != nullptr) |
113 | 0 | annuityWeights_.push_back(coupon->nominal() * coupon->accrualPeriod()); |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | | |
118 | | // constructor to map a swaption to deterministic fixed and floating leg cash flows |
119 | | SwaptionCashFlows::SwaptionCashFlows(const ext::shared_ptr<Swaption>& swaption, |
120 | | const Handle<YieldTermStructure>& discountCurve, |
121 | | bool contTenorSpread) |
122 | 0 | : SwapCashFlows(swaption->underlying(), discountCurve, contTenorSpread), |
123 | 0 | swaption_(swaption) { |
124 | | // assemble raw cash flow data... |
125 | 0 | Actual365Fixed dc; |
126 | | // ... exercise times |
127 | 0 | for (Size k = 0; k < swaption_->exercise()->dates().size(); ++k) |
128 | 0 | if (swaption_->exercise()->dates()[k] > refDate_) // consider only future exercise dates |
129 | 0 | exerciseTimes_.push_back( |
130 | 0 | dc.yearFraction(refDate_, swaption_->exercise()->dates()[k])); |
131 | 0 | } |
132 | | |
133 | | |
134 | | } |