Skip to content

Commit b8e4607

Browse files
committed
add time utilities to QuantLib, add a forecastFixing by time to IborIndex
1 parent 1c794a7 commit b8e4607

8 files changed

Lines changed: 211 additions & 2 deletions

File tree

QuantLib.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1845,6 +1845,7 @@
18451845
<ClInclude Include="ql\utilities\null_deleter.hpp" />
18461846
<ClInclude Include="ql\utilities\observablevalue.hpp" />
18471847
<ClInclude Include="ql\utilities\steppingiterator.hpp" />
1848+
<ClInclude Include="ql\utilities\time.hpp" />
18481849
<ClInclude Include="ql\utilities\tracing.hpp" />
18491850
<ClInclude Include="ql\utilities\vectors.hpp" />
18501851
<ClInclude Include="ql\auto_link.hpp" />
@@ -2793,6 +2794,7 @@
27932794
<ClCompile Include="ql\time\weekday.cpp" />
27942795
<ClCompile Include="ql\utilities\dataformatters.cpp" />
27952796
<ClCompile Include="ql\utilities\dataparsers.cpp" />
2797+
<ClInclude Include="ql\utilities\time.cpp" />
27962798
<ClCompile Include="ql\utilities\tracing.cpp" />
27972799
<ClCompile Include="ql\cashflow.cpp" />
27982800
<ClCompile Include="ql\currency.cpp" />

QuantLib.vcxproj.filters

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2244,7 +2244,10 @@
22442244
<ClInclude Include="ql\utilities\steppingiterator.hpp">
22452245
<Filter>utilities</Filter>
22462246
</ClInclude>
2247-
<ClInclude Include="ql\utilities\tracing.hpp">
2247+
<ClInclude Include="ql\utilities\time.hpp">
2248+
<Filter>utilities</Filter>
2249+
</ClInclude>
2250+
<ClInclude Include="ql\utilities\tracing.hpp">
22482251
<Filter>utilities</Filter>
22492252
</ClInclude>
22502253
<ClInclude Include="ql\utilities\vectors.hpp">
@@ -5531,6 +5534,9 @@
55315534
<ClCompile Include="ql\utilities\dataparsers.cpp">
55325535
<Filter>utilities</Filter>
55335536
</ClCompile>
5537+
<ClCompile Include="ql\utilities\time.cpp">
5538+
<Filter>utilities</Filter>
5539+
</ClCompile>
55345540
<ClCompile Include="ql\utilities\tracing.cpp">
55355541
<Filter>utilities</Filter>
55365542
</ClCompile>

ql/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,7 @@ set(QL_SOURCES
916916
timegrid.cpp
917917
utilities/dataformatters.cpp
918918
utilities/dataparsers.cpp
919+
utilities/time.cpp
919920
utilities/tracing.cpp
920921
version.cpp
921922
)
@@ -2186,6 +2187,7 @@ set(QL_HEADERS
21862187
utilities/null_deleter.hpp
21872188
utilities/observablevalue.hpp
21882189
utilities/steppingiterator.hpp
2190+
utilities/time.hpp
21892191
utilities/tracing.hpp
21902192
utilities/vectors.hpp
21912193
volatilitymodel.hpp

ql/indexes/iborindex.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include <ql/indexes/iborindex.hpp>
2323
#include <ql/termstructures/yieldtermstructure.hpp>
24+
#include <ql/utilities/time.hpp>
2425
#include <utility>
2526

2627
namespace QuantLib {
@@ -51,6 +52,17 @@ namespace QuantLib {
5152
return forecastFixing(d1, d2, t);
5253
}
5354

55+
Rate IborIndex::forecastFixing(const Time& fixingTime) const {
56+
QL_REQUIRE(fixingTime > 0.0, "\n cannot calculate forward rate, " \
57+
"fixing time must be positive");
58+
QL_REQUIRE(!termStructure_.empty(),
59+
"null term structure set to this instance of " << name());
60+
Time tenorTime = periodToTime(tenor_);
61+
DiscountFactor disc1 = termStructure_->discount(fixingTime);
62+
DiscountFactor disc2 = termStructure_->discount(fixingTime + tenorTime);
63+
return (disc1 / disc2 - 1.0) / tenorTime;
64+
}
65+
5466
Date IborIndex::maturityDate(const Date& valueDate) const {
5567
return fixingCalendar().advance(valueDate,
5668
tenor_,

ql/indexes/iborindex.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ namespace QuantLib {
4646
//! \name InterestRateIndex interface
4747
//@{
4848
Date maturityDate(const Date& valueDate) const override;
49-
Rate forecastFixing(const Date& fixingDate) const override;
49+
Rate forecastFixing(const Date& fixingDate) const override;
50+
Rate forecastFixing(const Time& fixingTime) const;
5051
// @}
5152
//! \name Inspectors
5253
//@{

ql/utilities/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ this_include_HEADERS = \
1212
null_deleter.hpp \
1313
observablevalue.hpp \
1414
steppingiterator.hpp \
15+
time.hpp \
1516
tracing.hpp \
1617
vectors.hpp
1718

1819
cpp_files = \
1920
dataformatters.cpp \
2021
dataparsers.cpp \
22+
time.cpp \
2123
tracing.cpp
2224

2325
if UNITY_BUILD

ql/utilities/time.cpp

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
Copyright (C) 2022 Quaternion Risk Management Ltd
3+
4+
This file is part of QuantLib, a free-software/open-source library
5+
for financial quantitative analysts and developers - http://quantlib.org/
6+
7+
QuantLib is free software: you can redistribute it and/or modify it
8+
under the terms of the QuantLib license. You should have received a
9+
copy of the license along with this program; if not, please email
10+
<quantlib-dev@lists.sf.net>. The license is also available online at
11+
<http://quantlib.org/license.shtml>.
12+
13+
This program is distributed in the hope that it will be useful, but WITHOUT
14+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15+
FOR A PARTICULAR PURPOSE. See the license for more details.
16+
*/
17+
18+
/*! \file qle/utilities/time.hpp
19+
\brief time related utilities.
20+
*/
21+
22+
#include <ql/errors.hpp>
23+
#include <ql/math/comparison.hpp>
24+
#include <ql/time/dategenerationrule.hpp>
25+
#include <ql/time/period.hpp>
26+
#include <ql/time/schedule.hpp>
27+
#include <ql/types.hpp>
28+
#include <ql/utilities/time.hpp>
29+
#include <vector>
30+
31+
namespace QuantLib {
32+
33+
Real periodToTime(const Period& p) {
34+
switch (p.units()) {
35+
case Days:
36+
return static_cast<Real>(p.length()) / 365.25;
37+
case Weeks:
38+
return static_cast<Real>(p.length()) * 7.0 / 365.25;
39+
case Months:
40+
return static_cast<Real>(p.length()) / 12.0;
41+
case Years:
42+
return static_cast<Real>(p.length());
43+
default:
44+
QL_FAIL("periodToTime(): time unit (" << p.units() << ") not handled");
45+
}
46+
}
47+
48+
QuantLib::Period implyIndexTerm(const Date& startDate, const Date& endDate) {
49+
static const std::vector<Period> eligibleTerms = {
50+
5 * Years, 7 * Years, 10 * Years, 3 * Years, 1 * Years,
51+
2 * Years, 4 * Years, 6 * Years, 8 * Years, 9 * Years};
52+
static const int gracePeriod = 15;
53+
54+
for (auto const& p : eligibleTerms) {
55+
if (std::abs(cdsMaturity(startDate, p, DateGeneration::CDS2015) - endDate) <
56+
gracePeriod) {
57+
return p;
58+
}
59+
}
60+
61+
return 0 * Days;
62+
}
63+
64+
QuantLib::Date
65+
lowerDate(const Real t, const QuantLib::Date& refDate, const QuantLib::DayCounter& dc) {
66+
if (close_enough(t, 0.0))
67+
return refDate;
68+
QL_REQUIRE(t > 0.0, "lowerDate("
69+
<< t << "," << refDate << "," << dc.name()
70+
<< ") was called with negative time, this is not allowed.");
71+
bool done = false;
72+
Date d = refDate + static_cast<int>(t * 365.25);
73+
Real tmp = dc.yearFraction(refDate, d);
74+
Size attempts = 0;
75+
while ((tmp < t || close_enough(tmp, t)) && (++attempts < 10000)) {
76+
++d;
77+
tmp = dc.yearFraction(refDate, d);
78+
done = true;
79+
}
80+
QL_REQUIRE(attempts < 10000, "lowerDate(" << t << "," << refDate << "," << dc.name()
81+
<< ") could not be computed.");
82+
if (done)
83+
return --d;
84+
while ((tmp > t && !close_enough(tmp, t)) && (++attempts < 10000)) {
85+
--d;
86+
tmp = dc.yearFraction(refDate, d);
87+
done = true;
88+
}
89+
QL_REQUIRE(attempts < 10000, "lowerDate(" << t << "," << refDate << "," << dc.name()
90+
<< ") could not be computed.");
91+
if (done)
92+
return d;
93+
QL_FAIL("lowerDate(" << t << "," << refDate << "," << dc.name()
94+
<< ") could not be computed.");
95+
}
96+
97+
QuantLib::Period tenorFromLength(const QuantLib::Real length) {
98+
if (std::abs(length - std::round(length)) < 1.0 / 365.25)
99+
return std::lround(length) * Years;
100+
if (std::abs(length * 12.0 - std::round(length * 12.0)) < 12.0 / 365.25)
101+
return std::lround(length * 12.0) * Months;
102+
return std::lround(length * 365.25) * Days;
103+
}
104+
105+
QuantLib::Integer daylightSavingCorrection(const std::string& location,
106+
const QuantLib::Date& start,
107+
const QuantLib::Date& end) {
108+
Integer result = 0;
109+
if (location == "Null") {
110+
result = 0;
111+
} else if (location == "US") {
112+
for (Integer y = start.year(); y <= end.year(); ++y) {
113+
Date d1 = Date::nthWeekday(2, Sunday, March, y);
114+
Date d2 = Date::nthWeekday(1, Sunday, November, y);
115+
if (start <= d1 && end > d1)
116+
--result;
117+
if (start <= d2 && end > d2)
118+
++result;
119+
}
120+
} else {
121+
QL_FAIL("daylightSavings("
122+
<< location
123+
<< ") not supported. Contact dev to add support for this location.");
124+
}
125+
return result;
126+
}
127+
128+
} // namespace QuantExt

ql/utilities/time.hpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
Copyright (C) 2022 Quaternion Risk Management Ltd
3+
4+
This file is part of QuantLib, a free-software/open-source library
5+
for financial quantitative analysts and developers - http://quantlib.org/
6+
7+
QuantLib is free software: you can redistribute it and/or modify it
8+
under the terms of the QuantLib license. You should have received a
9+
copy of the license along with this program; if not, please email
10+
<quantlib-dev@lists.sf.net>. The license is also available online at
11+
<http://quantlib.org/license.shtml>.
12+
13+
This program is distributed in the hope that it will be useful, but WITHOUT
14+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15+
FOR A PARTICULAR PURPOSE. See the license for more details.
16+
*/
17+
18+
/*! \file qle/utilities/time.hpp
19+
\brief time related utilities.
20+
*/
21+
22+
#pragma once
23+
24+
#include <ql/time/date.hpp>
25+
#include <ql/time/daycounter.hpp>
26+
#include <ql/time/period.hpp>
27+
28+
namespace QuantLib {
29+
30+
/* convert period to time using 1Y = 1, 1M = 1/12, 1W = 7/365, 1D = 1/365 */
31+
QuantLib::Real periodToTime(const QuantLib::Period& p);
32+
33+
/*! Imply cds index term from start and end date. If no reasonable term can be implied, 0 * Days
34+
* is returned */
35+
QuantLib::Period implyIndexTerm(const QuantLib::Date& startDate, const QuantLib::Date& endDate);
36+
37+
/* For t >= 0 get the largest date d such that dc.yearFraction(refDate, d) <= t. If the
38+
condition dc.yearFraction(refDate, d+1) > t is not met, an exception is thrown. */
39+
QuantLib::Date lowerDate(const QuantLib::Real t,
40+
const QuantLib::Date& refDate,
41+
const QuantLib::DayCounter& dc);
42+
43+
/* Find period such that the difference to length is < 1.0 / 365.25 and prefer unit years >
44+
* months > days */
45+
QuantLib::Period tenorFromLength(const QuantLib::Real length);
46+
47+
/* Get the accumulated daylight savings correction between two dates, both treated as "included"
48+
for different locations (see http://www.webexhibits.org/daylightsaving) Null no
49+
daylight saving, returns 0 always US Start: Second Sunday in March End : First
50+
Sunday in November
51+
*/
52+
QuantLib::Integer daylightSavingCorrection(const std::string& location,
53+
const QuantLib::Date& start,
54+
const QuantLib::Date& end);
55+
56+
} // namespace QuantExt

0 commit comments

Comments
 (0)