1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2020 StatPro Italia srl
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 "indexes.hpp"
21#include "utilities.hpp"
22#include <ql/indexes/bmaindex.hpp>
23#include <ql/indexes/ibor/euribor.hpp>
24#include <ql/time/calendars/target.hpp>
25#include <ql/time/daycounters/actual360.hpp>
26#include <ql/utilities/dataformatters.hpp>
27#include <boost/algorithm/string/case_conv.hpp>
28
29using namespace QuantLib;
30using namespace boost::unit_test_framework;
31
32void IndexTest::testFixingObservability() {
33 BOOST_TEST_MESSAGE("Testing observability of index fixings...");
34
35 ext::shared_ptr<InterestRateIndex> i1 = ext::make_shared<Euribor6M>();
36 ext::shared_ptr<InterestRateIndex> i2 = ext::make_shared<BMAIndex>();
37
38 Flag f1;
39 f1.registerWith(h: i1);
40 f1.lower();
41
42 Flag f2;
43 f2.registerWith(h: i2);
44 f2.lower();
45
46 Date today = Date::todaysDate();
47
48 ext::shared_ptr<Index> euribor = ext::make_shared<Euribor6M>();
49
50 Date d1 = today;
51 while (!euribor->isValidFixingDate(fixingDate: d1))
52 d1++;
53
54 euribor->addFixing(fixingDate: d1, fixing: -0.003);
55 if (!f1.isUp())
56 BOOST_FAIL("Observer was not notified of added Euribor fixing");
57
58 ext::shared_ptr<Index> bma = ext::make_shared<BMAIndex>();
59
60 Date d2 = today;
61 while (!bma->isValidFixingDate(fixingDate: d2))
62 d2++;
63
64 bma->addFixing(fixingDate: d2, fixing: 0.01);
65 if (!f2.isUp())
66 BOOST_FAIL("Observer was not notified of added BMA fixing");
67}
68
69void IndexTest::testFixingHasHistoricalFixing() {
70 BOOST_TEST_MESSAGE("Testing if index has historical fixings...");
71
72 auto testCase = [](const std::string& indexName, const bool& expected, const bool& testResult) {
73 if (expected != testResult) {
74 BOOST_FAIL("Historical fixing " << (testResult ? "" : "not ") << "found for "
75 << indexName << ".");
76 }
77 };
78
79 std::string name;
80 auto fixingFound = true;
81 auto fixingNotFound = false;
82
83 auto euribor3M = ext::make_shared<Euribor3M>();
84 auto euribor6M = ext::make_shared<Euribor6M>();
85 auto euribor6M_a = ext::make_shared<Euribor6M>();
86
87 Date today = Settings::instance().evaluationDate();
88 while (!euribor6M->isValidFixingDate(d: today))
89 today--;
90
91 euribor6M->addFixing(fixingDate: today, fixing: 0.01);
92
93 name = euribor3M->name();
94 testCase(name, fixingNotFound, euribor3M->hasHistoricalFixing(fixingDate: today));
95 testCase(name, fixingNotFound, IndexManager::instance().hasHistoricalFixing(name, fixingDate: today));
96 name = boost::to_upper_copy(Input: euribor3M->name());
97 testCase(name, fixingNotFound, IndexManager::instance().hasHistoricalFixing(name, fixingDate: today));
98 name = boost::to_lower_copy(Input: euribor3M->name());
99 testCase(name, fixingNotFound, IndexManager::instance().hasHistoricalFixing(name, fixingDate: today));
100
101 name = euribor6M->name();
102 testCase(name, fixingFound, euribor6M->hasHistoricalFixing(fixingDate: today));
103 testCase(name, fixingFound, euribor6M_a->hasHistoricalFixing(fixingDate: today));
104 testCase(name, fixingFound, IndexManager::instance().hasHistoricalFixing(name, fixingDate: today));
105 name = boost::to_upper_copy(Input: euribor6M->name());
106 testCase(name, fixingFound, IndexManager::instance().hasHistoricalFixing(name, fixingDate: today));
107 name = boost::to_lower_copy(Input: euribor6M->name());
108 testCase(name, fixingFound, IndexManager::instance().hasHistoricalFixing(name, fixingDate: today));
109
110 IndexManager::instance().clearHistories();
111
112 name = euribor3M->name();
113 testCase(name, fixingNotFound, euribor3M->hasHistoricalFixing(fixingDate: today));
114 testCase(name, fixingNotFound, IndexManager::instance().hasHistoricalFixing(name, fixingDate: today));
115 name = boost::to_upper_copy(Input: euribor3M->name());
116 testCase(name, fixingNotFound, IndexManager::instance().hasHistoricalFixing(name, fixingDate: today));
117 name = boost::to_lower_copy(Input: euribor3M->name());
118 testCase(name, fixingNotFound, IndexManager::instance().hasHistoricalFixing(name, fixingDate: today));
119
120 name = euribor6M->name();
121 testCase(name, fixingNotFound, euribor6M->hasHistoricalFixing(fixingDate: today));
122 testCase(name, fixingNotFound, euribor6M_a->hasHistoricalFixing(fixingDate: today));
123 testCase(name, fixingNotFound, IndexManager::instance().hasHistoricalFixing(name, fixingDate: today));
124 name = boost::to_upper_copy(Input: euribor6M->name());
125 testCase(name, fixingNotFound, IndexManager::instance().hasHistoricalFixing(name, fixingDate: today));
126 name = boost::to_lower_copy(Input: euribor6M->name());
127 testCase(name, fixingNotFound, IndexManager::instance().hasHistoricalFixing(name, fixingDate: today));
128}
129
130void IndexTest::testTenorNormalization() {
131 BOOST_TEST_MESSAGE("Testing that interest-rate index tenor is normalized correctly...");
132
133 auto i12m = IborIndex("foo", 12*Months, 2, Currency(),
134 TARGET(), Following, false, Actual360());
135 auto i1y = IborIndex("foo", 1*Years, 2, Currency(),
136 TARGET(), Following, false, Actual360());
137
138 if (i12m.name() != i1y.name())
139 BOOST_ERROR("12M index and 1Y index yield different names");
140
141
142 auto i6d = IborIndex("foo", 6*Days, 2, Currency(),
143 TARGET(), Following, false, Actual360());
144 auto i7d = IborIndex("foo", 7*Days, 2, Currency(),
145 TARGET(), Following, false, Actual360());
146
147 Date testDate(28, April, 2023);
148 Date maturity6d = i6d.maturityDate(valueDate: testDate);
149 Date maturity7d = i7d.maturityDate(valueDate: testDate);
150
151 if (maturity6d >= maturity7d) {
152 BOOST_ERROR("inconsistent maturity dates and tenors"
153 << "\n maturity date for 6-days index: " << maturity6d
154 << "\n maturity date for 7-days index: " << maturity7d);
155 }
156}
157
158test_suite* IndexTest::suite() {
159 auto* suite = BOOST_TEST_SUITE("index tests");
160 suite->add(QUANTLIB_TEST_CASE(&IndexTest::testFixingObservability));
161 suite->add(QUANTLIB_TEST_CASE(&IndexTest::testFixingHasHistoricalFixing));
162 suite->add(QUANTLIB_TEST_CASE(&IndexTest::testTenorNormalization));
163 return suite;
164}
165

source code of quantlib/test-suite/indexes.cpp