Coverage Report

Created: 2025-08-05 06:45

/src/quantlib/ql/cashflows/capflooredcoupon.hpp
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) 2006, 2007 StatPro Italia srl
5
 Copyright (C) 2006 Cristina Duminuco
6
7
 This file is part of QuantLib, a free-software/open-source library
8
 for financial quantitative analysts and developers - http://quantlib.org/
9
10
 QuantLib is free software: you can redistribute it and/or modify it
11
 under the terms of the QuantLib license.  You should have received a
12
 copy of the license along with this program; if not, please email
13
 <quantlib-dev@lists.sf.net>. The license is also available online at
14
 <http://quantlib.org/license.shtml>.
15
16
 This program is distributed in the hope that it will be useful, but WITHOUT
17
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 FOR A PARTICULAR PURPOSE.  See the license for more details.
19
*/
20
21
/*! \file capflooredcoupon.hpp
22
    \brief Floating rate coupon with additional cap/floor
23
*/
24
25
#ifndef quantlib_capped_floored_coupon_hpp
26
#define quantlib_capped_floored_coupon_hpp
27
28
#include <ql/cashflows/iborcoupon.hpp>
29
#include <ql/cashflows/cmscoupon.hpp>
30
#include <ql/utilities/null.hpp>
31
32
namespace QuantLib {
33
    class Date;
34
    //! Capped and/or floored floating-rate coupon
35
    /*! The payoff \f$ P \f$ of a capped floating-rate coupon is:
36
        \f[ P = N \times T \times \min(a L + b, C). \f]
37
        The payoff of a floored floating-rate coupon is:
38
        \f[ P = N \times T \times \max(a L + b, F). \f]
39
        The payoff of a collared floating-rate coupon is:
40
        \f[ P = N \times T \times \min(\max(a L + b, F), C). \f]
41
42
        where \f$ N \f$ is the notional, \f$ T \f$ is the accrual
43
        time, \f$ L \f$ is the floating rate, \f$ a \f$ is its
44
        gearing, \f$ b \f$ is the spread, and \f$ C \f$ and \f$ F \f$
45
        the strikes.
46
47
        They can be decomposed in the following manner.
48
        Decomposition of a capped floating rate coupon:
49
        \f[
50
        R = \min(a L + b, C) = (a L + b) + \min(C - b - \xi |a| L, 0)
51
        \f]
52
        where \f$ \xi = sgn(a) \f$. Then:
53
        \f[
54
        R = (a L + b) + |a| \min(\frac{C - b}{|a|} - \xi L, 0)
55
        \f]
56
    */
57
    class CappedFlooredCoupon : public FloatingRateCoupon {
58
      public:
59
        CappedFlooredCoupon(
60
                  const ext::shared_ptr<FloatingRateCoupon>& underlying,
61
                  Rate cap = Null<Rate>(),
62
                  Rate floor = Null<Rate>());
63
        //! \name Observer interface
64
        //@{
65
        void deepUpdate() override;
66
        //@}
67
        //! \name LazyObject interface
68
        //@{
69
        void performCalculations() const override;
70
        //@}
71
        //! \name Coupon interface
72
        //@{
73
        Rate rate() const override;
74
        Rate convexityAdjustment() const override;
75
        //@}
76
        //! cap
77
        Rate cap() const;
78
        //! floor
79
        Rate floor() const;
80
        //! effective cap of fixing
81
        Rate effectiveCap() const;
82
        //! effective floor of fixing
83
        Rate effectiveFloor() const;
84
        //@}
85
        //! \name Visitability
86
        //@{
87
        void accept(AcyclicVisitor&) override;
88
89
0
        bool isCapped() const {return isCapped_;}
90
0
        bool isFloored() const {return isFloored_;}
91
92
        void setPricer(const ext::shared_ptr<FloatingRateCouponPricer>& pricer) override;
93
94
0
        ext::shared_ptr<FloatingRateCoupon> underlying() { return underlying_; }
95
96
      protected:
97
        // data
98
        ext::shared_ptr<FloatingRateCoupon> underlying_;
99
        bool isCapped_ = false, isFloored_ = false;
100
        Rate cap_, floor_;
101
    };
102
103
    class CappedFlooredIborCoupon : public CappedFlooredCoupon {
104
      public:
105
        CappedFlooredIborCoupon(
106
                  const Date& paymentDate,
107
                  Real nominal,
108
                  const Date& startDate,
109
                  const Date& endDate,
110
                  Natural fixingDays,
111
                  const ext::shared_ptr<IborIndex>& index,
112
                  Real gearing = 1.0,
113
                  Spread spread = 0.0,
114
                  Rate cap = Null<Rate>(),
115
                  Rate floor = Null<Rate>(),
116
                  const Date& refPeriodStart = Date(),
117
                  const Date& refPeriodEnd = Date(),
118
                  const DayCounter& dayCounter = DayCounter(),
119
                  bool isInArrears = false,
120
                  const Date& exCouponDate = Date())
121
0
        : CappedFlooredCoupon(ext::shared_ptr<FloatingRateCoupon>(new
122
0
            IborCoupon(paymentDate, nominal, startDate, endDate, fixingDays,
123
0
                       index, gearing, spread, refPeriodStart, refPeriodEnd,
124
0
                       dayCounter, isInArrears, exCouponDate)), cap, floor) {}
125
126
0
        void accept(AcyclicVisitor& v) override {
127
0
            auto* v1 = dynamic_cast<Visitor<CappedFlooredIborCoupon>*>(&v);
128
0
            if (v1 != nullptr)
129
0
                v1->visit(*this);
130
0
            else
131
0
                CappedFlooredCoupon::accept(v);
132
0
        }
133
    };
134
135
    class CappedFlooredCmsCoupon : public CappedFlooredCoupon {
136
      public:
137
        CappedFlooredCmsCoupon(
138
                  const Date& paymentDate,
139
                  Real nominal,
140
                  const Date& startDate,
141
                  const Date& endDate,
142
                  Natural fixingDays,
143
                  const ext::shared_ptr<SwapIndex>& index,
144
                  Real gearing = 1.0,
145
                  Spread spread= 0.0,
146
                  const Rate cap = Null<Rate>(),
147
                  const Rate floor = Null<Rate>(),
148
                  const Date& refPeriodStart = Date(),
149
                  const Date& refPeriodEnd = Date(),
150
                  const DayCounter& dayCounter = DayCounter(),
151
                  bool isInArrears = false,
152
                  const Date& exCouponDate = Date())
153
0
        : CappedFlooredCoupon(ext::shared_ptr<FloatingRateCoupon>(new
154
0
            CmsCoupon(paymentDate, nominal, startDate, endDate, fixingDays,
155
0
                      index, gearing, spread, refPeriodStart, refPeriodEnd,
156
0
                      dayCounter, isInArrears, exCouponDate)), cap, floor) {}
157
158
0
        void accept(AcyclicVisitor& v) override {
159
0
            auto* v1 = dynamic_cast<Visitor<CappedFlooredCmsCoupon>*>(&v);
160
0
            if (v1 != nullptr)
161
0
                v1->visit(*this);
162
0
            else
163
0
                CappedFlooredCoupon::accept(v);
164
0
        }
165
    };
166
167
}
168
169
#endif