Coverage Report

Created: 2025-10-14 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/time/imm.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
5
 Copyright (C) 2003, 2004, 2005, 2006, 2007 StatPro Italia srl
6
 Copyright (C) 2004, 2005, 2006 Ferdinando Ametrano
7
 Copyright (C) 2006 Katiuscia Manzoni
8
9
 This file is part of QuantLib, a free-software/open-source library
10
 for financial quantitative analysts and developers - http://quantlib.org/
11
12
 QuantLib is free software: you can redistribute it and/or modify it
13
 under the terms of the QuantLib license.  You should have received a
14
 copy of the license along with this program; if not, please email
15
 <quantlib-dev@lists.sf.net>. The license is also available online at
16
 <https://www.quantlib.org/license.shtml>.
17
18
 This program is distributed in the hope that it will be useful, but WITHOUT
19
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20
 FOR A PARTICULAR PURPOSE.  See the license for more details.
21
*/
22
23
#include <ql/time/imm.hpp>
24
#include <ql/settings.hpp>
25
#include <ql/utilities/dataparsers.hpp>
26
#include <boost/algorithm/string/case_conv.hpp>
27
#include <string>
28
29
using boost::algorithm::to_upper_copy;
30
using std::string;
31
32
namespace QuantLib {
33
34
0
    bool IMM::isIMMdate(const Date& date, bool mainCycle) {
35
0
        if (date.weekday()!=Wednesday)
36
0
            return false;
37
38
0
        Day d = date.dayOfMonth();
39
0
        if (d<15 || d>21)
40
0
            return false;
41
42
0
        if (!mainCycle) return true;
43
44
0
        switch (date.month()) {
45
0
          case March:
46
0
          case June:
47
0
          case September:
48
0
          case December:
49
0
            return true;
50
0
          default:
51
0
            return false;
52
0
        }
53
0
    }
54
55
0
    bool IMM::isIMMcode(const std::string& in, bool mainCycle) {
56
0
        if (in.length() != 2)
57
0
            return false;
58
59
0
        string str1("0123456789");
60
0
        string::size_type loc = str1.find(in.substr(1,1), 0);
61
0
        if (loc == string::npos)
62
0
            return false;
63
64
0
        if (mainCycle) str1 = "hmzuHMZU";
65
0
        else           str1 = "fghjkmnquvxzFGHJKMNQUVXZ";
66
0
        loc = str1.find(in.substr(0,1), 0);
67
0
        return loc != string::npos;
68
0
    }
69
70
0
    std::string IMM::code(const Date& date) {
71
0
        QL_REQUIRE(isIMMdate(date, false),
72
0
                   date << " is not an IMM date");
73
74
0
        std::ostringstream IMMcode;
75
0
        unsigned int y = date.year() % 10;
76
0
        switch(date.month()) {
77
0
          case January:
78
0
            IMMcode << 'F' << y;
79
0
            break;
80
0
          case February:
81
0
            IMMcode << 'G' << y;
82
0
            break;
83
0
          case March:
84
0
            IMMcode << 'H' << y;
85
0
            break;
86
0
          case April:
87
0
            IMMcode << 'J' << y;
88
0
            break;
89
0
          case May:
90
0
            IMMcode << 'K' << y;
91
0
            break;
92
0
          case June:
93
0
            IMMcode << 'M' << y;
94
0
            break;
95
0
          case July:
96
0
            IMMcode << 'N' << y;
97
0
            break;
98
0
          case August:
99
0
            IMMcode << 'Q' << y;
100
0
            break;
101
0
          case September:
102
0
            IMMcode << 'U' << y;
103
0
            break;
104
0
          case October:
105
0
            IMMcode << 'V' << y;
106
0
            break;
107
0
          case November:
108
0
            IMMcode << 'X' << y;
109
0
            break;
110
0
          case December:
111
0
            IMMcode << 'Z' << y;
112
0
            break;
113
0
          default:
114
0
            QL_FAIL("not an IMM month (and it should have been)");
115
0
        }
116
117
        #if defined(QL_EXTRA_SAFETY_CHECKS)
118
        QL_ENSURE(isIMMcode(IMMcode.str(), false),
119
                  "the result " << IMMcode.str() <<
120
                  " is an invalid IMM code");
121
        #endif
122
0
        return IMMcode.str();
123
0
    }
124
125
    Date IMM::date(const std::string& immCode,
126
0
                   const Date& refDate) {
127
0
        QL_REQUIRE(isIMMcode(immCode, false),
128
0
                   immCode << " is not a valid IMM code");
129
130
0
        Date referenceDate = (refDate != Date() ?
131
0
                              refDate :
132
0
                              Date(Settings::instance().evaluationDate()));
133
134
0
        std::string code = to_upper_copy(immCode);
135
0
        std::string ms = code.substr(0,1);
136
0
        QuantLib::Month m;
137
0
        if (ms=="F")      m = January;
138
0
        else if (ms=="G") m = February;
139
0
        else if (ms=="H") m = March;
140
0
        else if (ms=="J") m = April;
141
0
        else if (ms=="K") m = May;
142
0
        else if (ms=="M") m = June;
143
0
        else if (ms=="N") m = July;
144
0
        else if (ms=="Q") m = August;
145
0
        else if (ms=="U") m = September;
146
0
        else if (ms=="V") m = October;
147
0
        else if (ms=="X") m = November;
148
0
        else if (ms=="Z") m = December;
149
0
        else QL_FAIL("invalid IMM month letter");
150
151
0
        Year y = std::stoi(code.substr(1,1));
152
        /* year<1900 are not valid QuantLib years: to avoid a run-time
153
           exception few lines below we need to add 10 years right away */
154
0
        if (y==0 && referenceDate.year()<=1909) y+=10;
155
0
        Year referenceYear = (referenceDate.year() % 10);
156
0
        y += referenceDate.year() - referenceYear;
157
0
        Date result = IMM::nextDate(Date(1, m, y), false);
158
0
        if (result<referenceDate)
159
0
            return IMM::nextDate(Date(1, m, y+10), false);
160
161
0
        return result;
162
0
    }
163
164
0
    Date IMM::nextDate(const Date& date, bool mainCycle) {
165
0
        Date refDate = (date == Date() ?
166
0
                        Date(Settings::instance().evaluationDate()) :
167
0
                        date);
168
0
        Year y = refDate.year();
169
0
        QuantLib::Month m = refDate.month();
170
171
0
        Size offset = mainCycle ? 3 : 1;
172
0
        Size skipMonths = offset-(m%offset);
173
0
        if (skipMonths != offset || refDate.dayOfMonth() > 21) {
174
0
            skipMonths += Size(m);
175
0
            if (skipMonths<=12) {
176
0
                m = QuantLib::Month(skipMonths);
177
0
            } else {
178
0
                m = QuantLib::Month(skipMonths-12);
179
0
                y += 1;
180
0
            }
181
0
        }
182
183
0
        Date result = Date::nthWeekday(3, Wednesday, m, y);
184
0
        if (result<=refDate)
185
0
            result = nextDate(Date(22, m, y), mainCycle);
186
0
        return result;
187
0
    }
188
189
    Date IMM::nextDate(const std::string& IMMcode,
190
                       bool mainCycle,
191
0
                       const Date& referenceDate)  {
192
0
        Date immDate = date(IMMcode, referenceDate);
193
0
        return nextDate(immDate+1, mainCycle);
194
0
    }
195
196
    std::string IMM::nextCode(const Date& d,
197
0
                              bool mainCycle) {
198
0
        Date date = nextDate(d, mainCycle);
199
0
        return code(date);
200
0
    }
201
202
    std::string IMM::nextCode(const std::string& immCode,
203
                              bool mainCycle,
204
0
                              const Date& referenceDate) {
205
0
        Date date = nextDate(immCode, mainCycle, referenceDate);
206
0
        return code(date);
207
0
    }
208
209
}