Coverage Report

Created: 2025-09-04 07:11

/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
}