Coverage Report

Created: 2025-08-05 06:45

/src/quantlib/ql/cashflows/inflationcouponpricer.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) 2009 Chris Kenyon
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
 <http://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
#include <ql/cashflows/inflationcouponpricer.hpp>
21
#include <ql/pricingengines/blackformula.hpp>
22
#include <ql/termstructures/volatility/inflation/yoyinflationoptionletvolatilitystructure.hpp>
23
#include <utility>
24
25
namespace QuantLib {
26
27
    void setCouponPricer(const Leg& leg,
28
0
                         const ext::shared_ptr<InflationCouponPricer>& p) {
29
0
        for (const auto& i : leg) {
30
0
            ext::shared_ptr<InflationCoupon> c = ext::dynamic_pointer_cast<InflationCoupon>(i);
31
0
            if (c != nullptr)
32
0
                c->setPricer(p);
33
0
        }
34
0
    }
35
36
37
    YoYInflationCouponPricer::YoYInflationCouponPricer(
38
        Handle<YieldTermStructure> nominalTermStructure)
39
0
    : nominalTermStructure_(std::move(nominalTermStructure)) {
40
0
        registerWith(nominalTermStructure_);
41
0
    }
Unexecuted instantiation: QuantLib::YoYInflationCouponPricer::YoYInflationCouponPricer(QuantLib::Handle<QuantLib::YieldTermStructure>)
Unexecuted instantiation: QuantLib::YoYInflationCouponPricer::YoYInflationCouponPricer(QuantLib::Handle<QuantLib::YieldTermStructure>)
42
43
    YoYInflationCouponPricer::YoYInflationCouponPricer(
44
        Handle<YoYOptionletVolatilitySurface> capletVol,
45
        Handle<YieldTermStructure> nominalTermStructure)
46
0
    : capletVol_(std::move(capletVol)), nominalTermStructure_(std::move(nominalTermStructure)) {
47
0
        registerWith(capletVol_);
48
0
        registerWith(nominalTermStructure_);
49
0
    }
Unexecuted instantiation: QuantLib::YoYInflationCouponPricer::YoYInflationCouponPricer(QuantLib::Handle<QuantLib::YoYOptionletVolatilitySurface>, QuantLib::Handle<QuantLib::YieldTermStructure>)
Unexecuted instantiation: QuantLib::YoYInflationCouponPricer::YoYInflationCouponPricer(QuantLib::Handle<QuantLib::YoYOptionletVolatilitySurface>, QuantLib::Handle<QuantLib::YieldTermStructure>)
50
51
52
    void YoYInflationCouponPricer::setCapletVolatility(
53
0
       const Handle<YoYOptionletVolatilitySurface>& capletVol) {
54
0
        QL_REQUIRE(!capletVol.empty(),"empty capletVol handle");
55
0
        capletVol_ = capletVol;
56
0
        registerWith(capletVol_);
57
0
    }
58
59
60
0
    Real YoYInflationCouponPricer::floorletPrice(Rate effectiveFloor) const{
61
0
        Real floorletPrice = optionletPrice(Option::Put, effectiveFloor);
62
0
        return gearing_ * floorletPrice;
63
0
    }
64
65
0
    Real YoYInflationCouponPricer::capletPrice(Rate effectiveCap) const{
66
0
        Real capletPrice = optionletPrice(Option::Call, effectiveCap);
67
0
        return gearing_ * capletPrice;
68
0
    }
69
70
71
0
    Rate YoYInflationCouponPricer::floorletRate(Rate effectiveFloor) const{
72
0
        return gearing_ * optionletRate(Option::Put, effectiveFloor);
73
0
    }
74
75
0
    Rate YoYInflationCouponPricer::capletRate(Rate effectiveCap) const{
76
0
        return gearing_ * optionletRate(Option::Call, effectiveCap);
77
0
    }
78
79
80
    Real YoYInflationCouponPricer::optionletPriceImp(
81
                                                    Option::Type,
82
                                                    Real,
83
                                                    Real,
84
0
                                                    Real) const {
85
0
        QL_FAIL("you must implement this to get a vol-dependent price");
86
0
    }
87
88
89
    Real YoYInflationCouponPricer::optionletPrice(Option::Type optionType,
90
0
                                                  Real effStrike) const {
91
0
        QL_REQUIRE(discount_ != Null<Real>(), "no nominal term structure provided");
92
0
        return optionletRate(optionType, effStrike) * coupon_->accrualPeriod() * discount_;
93
0
    }
94
95
96
    Real YoYInflationCouponPricer::optionletRate(Option::Type optionType,
97
0
                                                 Real effStrike) const {
98
0
        Date fixingDate = coupon_->fixingDate();
99
0
        if (fixingDate <= capletVolatility()->baseDate()) {
100
            // the amount is determined
101
0
            Real a, b;
102
0
            if (optionType==Option::Call) {
103
0
                a = coupon_->indexFixing();
104
0
                b = effStrike;
105
0
            } else {
106
0
                a = effStrike;
107
0
                b = coupon_->indexFixing();
108
0
            }
109
0
            return std::max(a - b, 0.0);
110
0
        } else {
111
            // not yet determined, use Black/DD1/Bachelier/whatever from Impl
112
0
            QL_REQUIRE(!capletVolatility().empty(), "missing optionlet volatility");
113
114
0
            Real stdDev =
115
0
                std::sqrt(capletVolatility()->totalVariance(fixingDate,
116
0
                                                            effStrike,
117
0
                                                            Period(0, Days)));
118
0
            return optionletPriceImp(optionType,
119
0
                                     effStrike,
120
0
                                     adjustedFixing(),
121
0
                                     stdDev);
122
0
        }
123
0
    }
124
125
126
0
    Rate YoYInflationCouponPricer::adjustedFixing(Rate fixing) const {
127
128
0
        if (fixing == Null<Rate>())
129
0
            fixing = coupon_->indexFixing();
130
131
        // no adjustment
132
0
        return fixing;
133
0
    }
134
135
136
0
    void YoYInflationCouponPricer::initialize(const InflationCoupon& coupon) {
137
0
        coupon_ = dynamic_cast<const YoYInflationCoupon*>(&coupon);
138
0
        QL_REQUIRE(coupon_, "year-on-year inflation coupon needed");
139
0
        gearing_ = coupon_->gearing();
140
0
        spread_ = coupon_->spread();
141
0
        paymentDate_ = coupon_->date();
142
143
        // past or future fixing is managed in YoYInflationIndex::fixing()
144
        // use yield curve from index (which sets discount)
145
146
0
        discount_ = 1.0;
147
0
        if (nominalTermStructure_.empty()) {
148
            // allow to extract rates, but mark the discount as invalid for prices
149
0
            discount_ = Null<Real>();
150
0
        } else {
151
0
            if (paymentDate_ > nominalTermStructure_->referenceDate())
152
0
                discount_ = nominalTermStructure_->discount(paymentDate_);
153
0
        }
154
0
    }
155
156
157
0
    Real YoYInflationCouponPricer::swapletPrice() const {
158
0
        QL_REQUIRE(discount_ != Null<Real>(), "no nominal term structure provided");
159
0
        return swapletRate() * coupon_->accrualPeriod() * discount_;
160
0
    }
161
162
163
0
    Rate YoYInflationCouponPricer::swapletRate() const {
164
        // This way we do not require the index to have
165
        // a yield curve, i.e. we do not get the problem
166
        // that a discounting-instrument-pricer is used
167
        // with a different yield curve
168
0
        return gearing_ * adjustedFixing() + spread_;
169
0
    }
170
171
172
    //=========================================================================
173
    // vol-dependent pricers, note that these do not discount
174
    //=========================================================================
175
176
177
178
    Real BlackYoYInflationCouponPricer::optionletPriceImp(Option::Type optionType,
179
                                                     Real  effStrike,
180
                                                     Real  forward,
181
                                                     Real stdDev
182
0
                                                     ) const {
183
184
0
        return blackFormula(optionType,
185
0
                            effStrike,
186
0
                            forward,
187
0
                            stdDev);
188
0
    }
189
190
    Real UnitDisplacedBlackYoYInflationCouponPricer::optionletPriceImp(Option::Type optionType,
191
                                                                  Real  effStrike,
192
                                                                  Real  forward,
193
                                                                  Real stdDev
194
0
                                                          ) const {
195
196
0
        return blackFormula(optionType,
197
0
                            effStrike + 1.0,
198
0
                            forward + 1.0,
199
0
                            stdDev);
200
0
    }
201
202
    Real BachelierYoYInflationCouponPricer::optionletPriceImp(Option::Type optionType,
203
                                                              Real  effStrike,
204
                                                              Real  forward,
205
                                                              Real stdDev
206
0
                                                          ) const {
207
0
        return bachelierBlackFormula(optionType,
208
0
                                     effStrike,
209
0
                                     forward,
210
0
                                     stdDev);
211
0
    }
212
213
}