Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
fixingmanager.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2017 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
25
33
34#include <ql/cashflows/averagebmacoupon.hpp>
35#include <ql/cashflows/capflooredcoupon.hpp>
36#include <ql/cashflows/cpicoupon.hpp>
37#include <ql/cashflows/floatingratecoupon.hpp>
38#include <ql/cashflows/yoyinflationcoupon.hpp>
39#include <ql/experimental/coupons/cmsspreadcoupon.hpp>
40#include <ql/experimental/coupons/digitalcmsspreadcoupon.hpp>
41
42using namespace std;
43using namespace QuantLib;
44using namespace QuantExt;
45using namespace ore::data;
46
47namespace ore {
48namespace analytics {
49
50// Search for a valid fixing date maximum gap days larger than d, the only relevant case for this so far is BMA/SIFMA
51Date nextValidFixingDate(Date d, const QuantLib::ext::shared_ptr<Index>& index, Size gap = 7) {
52 Date adjusted = d;
53 for (Size i = 0; i <= gap; ++i) {
54 adjusted = d + i;
55 if (index->isValidFixingDate(adjusted))
56 return adjusted;
57 }
58 QL_FAIL("no valid fixing date found for index " << index->name() << " within gap from " << io::iso_date(d));
59}
60
61FixingManager::FixingManager(Date today) : today_(today), fixingsEnd_(today), modifiedFixingHistory_(false) {}
62
63//! Initialise the manager-
64
65void FixingManager::initialise(const QuantLib::ext::shared_ptr<Portfolio>& portfolio, const QuantLib::ext::shared_ptr<Market>& market,
66 const std::string& configuration) {
67
68 // populate the map "Index -> set of required fixing dates", where the index on the LHS is linked to curves
69 for (auto const& [tradeId,t] : portfolio->trades()) {
70 auto r = t->requiredFixings();
71 r.unsetPayDates();
72 for (auto const& [name, fixingDates] : r.fixingDatesIndices(QuantLib::Date::maxDate())) {
73 std::set<Date> dates;
74 for (const auto& [d, _] : fixingDates) {
75 dates.insert(d);
76 }
77 try {
78 auto rawIndex = parseIndex(name);
79 if (auto index = QuantLib::ext::dynamic_pointer_cast<EquityIndex2>(rawIndex)) {
80
81 fixingMap_[*market->equityCurve(index->familyName(), configuration)].insert(dates.begin(),
82 dates.end());
83 } else if (auto index = QuantLib::ext::dynamic_pointer_cast<BondIndex>(rawIndex)) {
84 QL_FAIL("BondIndex not handled");
85 } else if (auto index = QuantLib::ext::dynamic_pointer_cast<CommodityIndex>(rawIndex)) {
86 // for comm indices with non-daily expiries the expiry date's day of month is 1 always
87 Date safeExpiryDate = index->expiryDate();
88 if (safeExpiryDate != Date() && !index->keepDays()) {
89 safeExpiryDate = Date::endOfMonth(safeExpiryDate);
90 }
91 fixingMap_[index->clone(safeExpiryDate,
92 market->commodityPriceCurve(index->underlyingName(), configuration))]
93 .insert(dates.begin(), dates.end());
94 } else if (auto index = QuantLib::ext::dynamic_pointer_cast<FxIndex>(rawIndex)) {
95 fixingMap_[*market->fxIndex(index->oreName(), configuration)].insert(dates.begin(), dates.end());
96 } else if (auto index = QuantLib::ext::dynamic_pointer_cast<GenericIndex>(rawIndex)) {
97 QL_FAIL("GenericIndex not handled");
98 } else if (auto index = QuantLib::ext::dynamic_pointer_cast<ConstantMaturityBondIndex>(rawIndex)) {
99 QL_FAIL("ConstantMaturityBondIndex not handled");
100 } else if (auto index = QuantLib::ext::dynamic_pointer_cast<IborIndex>(rawIndex)) {
101 fixingMap_[*market->iborIndex(name, configuration)].insert(dates.begin(), dates.end());
102 } else if (auto index = QuantLib::ext::dynamic_pointer_cast<SwapIndex>(rawIndex)) {
103 fixingMap_[*market->swapIndex(name, configuration)].insert(dates.begin(), dates.end());
104 } else if (auto index = QuantLib::ext::dynamic_pointer_cast<ZeroInflationIndex>(rawIndex)) {
105 fixingMap_[*market->zeroInflationIndex(name, configuration)].insert(dates.begin(), dates.end());
106 }
107 } catch (const std::exception& e) {
108 ALOG("FixingManager: error " << e.what() << " - no fixings are added for '" << name << "'");
109 }
110 TLOG("Added " << dates.size() << " fixing dates for '" << name << "'");
111 }
112 }
113
114 // Now cache the original fixings so we can re-write on reset()
115 for (auto const& m : fixingMap_) {
116 fixingCache_[m.first] = IndexManager::instance().getHistory(m.first->name());
117 }
118}
119
120//! Update fixings to date d
122 if (!fixingMap_.empty()) {
123 QL_REQUIRE(d >= fixingsEnd_, "Can't go back in time, fixings must be reset."
124 " Update date "
125 << d << " but current fixings go to " << fixingsEnd_);
126 if (d > fixingsEnd_)
128 }
129 fixingsEnd_ = d;
130}
131
132//! Reset fixings to t0 (today)
135 for (auto& kv : fixingCache_)
136 IndexManager::instance().setHistory(kv.first->name(), kv.second);
138 }
140}
141
142void FixingManager::applyFixings(Date start, Date end) {
143 // Loop over all indices
144 for (auto const& m : fixingMap_) {
145 Date fixStart = start;
146 Date fixEnd = end;
147 Date currentFixingDate;
148 if (auto zii = QuantLib::ext::dynamic_pointer_cast<ZeroInflationIndex>(m.first)) {
149 fixStart =
150 inflationPeriod(fixStart - zii->zeroInflationTermStructure()->observationLag(), zii->frequency()).first;
151 fixEnd =
152 inflationPeriod(fixEnd - zii->zeroInflationTermStructure()->observationLag(), zii->frequency()).first +
153 1;
154 currentFixingDate = fixEnd;
155 } else if (auto yii = QuantLib::ext::dynamic_pointer_cast<YoYInflationIndex>(m.first)) {
156 fixStart =
157 inflationPeriod(fixStart - yii->yoyInflationTermStructure()->observationLag(), yii->frequency()).first;
158 fixEnd =
159 inflationPeriod(fixEnd - yii->yoyInflationTermStructure()->observationLag(), yii->frequency()).first +
160 1;
161 currentFixingDate = fixEnd;
162 } else {
163 currentFixingDate = m.first->fixingCalendar().adjust(fixEnd, Following);
164 // This date is a business day but may not be a valid fixing date in case of BMA/SIFMA
165 if (!m.first->isValidFixingDate(currentFixingDate))
166 currentFixingDate = nextValidFixingDate(currentFixingDate, m.first);
167 }
168
169 // Add we have a coupon between start and asof.
170 bool needFixings = false;
171 for (auto const& d : m.second) {
172 if (d >= fixStart && d < fixEnd) {
173 needFixings = true;
174 break;
175 }
176 }
177
178 if (needFixings) {
179 Rate currentFixing;
180 if (auto comm = QuantLib::ext::dynamic_pointer_cast<QuantExt::CommodityIndex>(m.first);
181 comm != nullptr && comm->expiryDate() < currentFixingDate) {
182 currentFixing = comm->priceCurve()->price(currentFixingDate);
183 } else {
184 currentFixing = m.first->fixing(currentFixingDate);
185 }
186 // if we read the fixing from an inverted FxIndex we have to undo the inversion
187 TimeSeries<Real> history;
188 for (auto const& d : m.second) {
189 if (d >= fixStart && d < fixEnd) {
190 // Fixing dates include the valuation grid dates which might not be valid fixing dates (BMA/SIFMA)
191 bool valid = m.first->isValidFixingDate(d);
192 if (valid) {
193 history[d] = currentFixing;
195 }
196 }
197 if (d >= fixEnd)
198 break;
199 }
200 m.first->addFixings(history, true);
201 }
202 }
203}
204
205} // namespace analytics
206} // namespace ore
void applyFixings(Date start, Date end)
void update(Date d)
Update fixings to date d.
void initialise(const QuantLib::ext::shared_ptr< Portfolio > &portfolio, const QuantLib::ext::shared_ptr< Market > &market, const std::string &configuration=Market::defaultConfiguration)
Initialise the manager with these flows and indices from the given portfolio.
void reset()
Reset fixings to t0 (today)
Controls the updating/reset of the QuantLib::IndexManager.
QuantLib::ext::shared_ptr< Index > parseIndex(const string &s)
#define ALOG(text)
#define TLOG(text)
Date nextValidFixingDate(Date d, const QuantLib::ext::shared_ptr< Index > &index, Size gap=7)
string name