Coverage Report

Created: 2025-11-04 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/time/calendars/russia.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2010 StatPro Italia srl
5
 Copyright (C) 2015 Dmitri Nesteruk
6
7
 This file is part of QuantLib, a free-software/open-source library
8
 for financial quantitative analysts and developers - http://quantlib.org/
9
10
 QuantLib is free software: you can redistribute it and/or modify it
11
 under the terms of the QuantLib license.  You should have received a
12
 copy of the license along with this program; if not, please email
13
 <quantlib-dev@lists.sf.net>. The license is also available online at
14
 <https://www.quantlib.org/license.shtml>.
15
16
 This program is distributed in the hope that it will be useful, but WITHOUT
17
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 FOR A PARTICULAR PURPOSE.  See the license for more details.
19
*/
20
21
#include <ql/time/calendars/russia.hpp>
22
#include <ql/errors.hpp>
23
24
namespace QuantLib {
25
26
0
    Russia::Russia(Russia::Market market) {
27
        // all calendar instances share the same implementation instance
28
0
        static ext::shared_ptr<Calendar::Impl> settlementImpl(
29
0
                                                  new Russia::SettlementImpl);
30
0
        static ext::shared_ptr<Calendar::Impl> exchangeImpl(
31
0
                                                    new Russia::ExchangeImpl);
32
33
0
        switch (market) {
34
0
          case Settlement:
35
0
            impl_ = settlementImpl;
36
0
            break;
37
0
          case MOEX:
38
0
            impl_ = exchangeImpl;
39
0
            break;
40
0
          default:
41
0
            QL_FAIL("unknown market");
42
0
        }
43
0
    }
44
45
    namespace {
46
47
0
        bool isExtraHolidaySettlementImpl(Day d, Month month, Year year) {
48
0
            switch (year) {
49
0
              case 2017:
50
0
                switch (month) {
51
0
                  case February: return d == 24;
52
0
                  case May:      return d == 8;
53
0
                  case November: return d == 6;
54
0
                  default:       return false;
55
0
                }
56
0
              case 2018:
57
0
                switch (month) {
58
0
                  case March:     return d == 9;
59
0
                  case April:     return d == 30;
60
0
                  case May:       return d == 2;
61
0
                  case June:      return d == 11;
62
0
                  case December:  return d == 31;
63
0
                  default:        return false;
64
0
                }
65
0
              case 2019:
66
0
                switch (month) {
67
0
                  case May: return d == 2 || d == 3 || d == 10;
68
0
                  default: return false;
69
0
                }
70
0
              case 2020:
71
0
                switch (month) {
72
0
                  case March:     return d == 30 || d == 31;
73
0
                  case April:     return d == 1 || d == 2 || d == 3;
74
0
                  case May:       return d == 4 || d == 5;
75
0
                  default:        return false;
76
0
                }
77
0
              default:
78
0
                return false;
79
0
            }
80
0
        }
81
82
    }
83
84
0
    bool Russia::SettlementImpl::isBusinessDay(const Date& date) const {
85
0
        Weekday w = date.weekday();
86
0
        Day d = date.dayOfMonth();
87
0
        Month m = date.month();
88
0
        Year y = date.year();
89
0
        if (isWeekend(w)
90
            // New Year's holidays
91
0
            || (y <= 2005 && d <= 2 && m == January)
92
0
            || (y >= 2005 && d <= 5 && m == January)
93
            // in 2012, the 6th was also a holiday
94
0
            || (y == 2012 && d == 6 && m == January)
95
            // Christmas (possibly moved to Monday)
96
0
            || ((d == 7 || ((d == 8 || d == 9) && w == Monday)) &&
97
0
                m == January)
98
            // Defender of the Fatherland Day (possibly moved to Monday)
99
0
            || ((d == 23 || ((d == 24 || d == 25) && w == Monday)) &&
100
0
                m == February)
101
            // International Women's Day (possibly moved to Monday)
102
0
            || ((d == 8 || ((d == 9 || d == 10) && w == Monday)) &&
103
0
                m == March)
104
            // Labour Day (possibly moved to Monday)
105
0
            || ((d == 1 || ((d == 2 || d == 3) && w == Monday)) &&
106
0
                m == May)
107
            // Victory Day (possibly moved to Monday)
108
0
            || ((d == 9 || ((d == 10 || d == 11) && w == Monday)) &&
109
0
                m == May)
110
            // Russia Day (possibly moved to Monday)
111
0
            || ((d == 12 || ((d == 13 || d == 14) && w == Monday)) &&
112
0
                m == June)
113
            // Unity Day (possibly moved to Monday)
114
0
            || ((d == 4 || ((d == 5 || d == 6) && w == Monday)) &&
115
0
                m == November))
116
0
            return false; // NOLINT(readability-simplify-boolean-expr)
117
118
0
        if (isExtraHolidaySettlementImpl(d,m,y))
119
0
            return false;
120
121
0
        return true;
122
0
    }
123
124
    namespace {
125
126
0
        bool isWorkingWeekend(Day d, Month month, Year year) {
127
0
            switch (year) {
128
0
              case 2012:
129
0
                switch (month) {
130
0
                  case March: return d == 11;
131
0
                  case April: return d == 28;
132
0
                  case May:   return d == 5 || d == 12;
133
0
                  case June:  return d == 9;
134
0
                  default:    return false;
135
0
                }
136
0
              case 2016:
137
0
                switch (month)
138
0
                {
139
0
                case February: return d == 20;
140
0
                default: return false;
141
0
                }
142
0
              case 2018:
143
0
                switch (month) {
144
0
                  case April: return d == 28;
145
0
                  case June: return d == 9;
146
0
                  case December: return d == 29;
147
0
                  default: return false;
148
0
                }
149
0
              default:
150
0
                return false;
151
0
            }
152
0
        }
153
154
0
        bool isExtraHolidayExchangeImpl(Day d, Month month, Year year) {
155
0
            switch (year) {
156
0
              case 2012:
157
0
                switch (month) {
158
0
                  case January: return d == 2;
159
0
                  case March:   return d == 9;
160
0
                  case April:   return d == 30;
161
0
                  case June:    return d == 11;
162
0
                  default:      return false;
163
0
                }
164
0
              case 2013:
165
0
                switch (month) {
166
0
                  case January: return d == 1 || d == 2 || d == 3
167
0
                                    || d == 4 || d == 7;
168
0
                  default:      return false;
169
0
                }
170
0
              case 2014:
171
0
                switch (month) {
172
0
                  case January: return d == 1 || d == 2 || d == 3 || d == 7;
173
0
                  default:      return false;
174
0
                }
175
0
              case 2015:
176
0
                switch (month) {
177
0
                  case January: return d == 1 || d == 2 || d == 7;
178
0
                  default:      return false;
179
0
                }
180
0
              case 2016:
181
0
                switch (month)
182
0
                {
183
0
                case January: return d == 1 || d == 7 || d == 8;
184
0
                case May:     return d == 2 || d == 3;
185
0
                case June:    return d == 13;
186
0
                case December: return d == 30;
187
0
                default:      return false;
188
0
                }
189
0
              case 2017:
190
0
                switch (month) {
191
0
                  case January: return d == 2;
192
0
                  case May:     return d == 8;
193
0
                  default:      return false;
194
0
                }
195
0
              case 2018:
196
0
                switch (month) {
197
0
                  case January:   return d == 1 || d == 2 || d == 8;
198
0
                  case December:  return d == 31;
199
0
                  default:        return false;
200
0
                }
201
0
              case 2019:
202
0
                switch (month) {
203
0
                case January:   return d == 1 || d == 2 || d == 7;
204
0
                case December:  return d == 31;
205
0
                default:        return false;
206
0
                }
207
0
              case 2020:
208
0
                switch (month) {
209
0
                  case January:   return d == 1 || d == 2 || d == 7;
210
0
                  case February:  return d == 24;
211
0
                  case June:      return d == 24;
212
0
                  case July:      return d == 1;
213
0
                  default:        return false;
214
0
                }
215
0
              default:
216
0
                return false;
217
0
            }
218
0
        }
219
220
    }
221
222
0
    bool Russia::ExchangeImpl::isBusinessDay(const Date& date) const {
223
0
        Weekday w = date.weekday();
224
0
        Day d = date.dayOfMonth();
225
0
        Month m = date.month();
226
0
        Year y = date.year();
227
228
        // the exchange was formally established in 2011, so data are only
229
        // available from 2012 to present
230
0
        if (y < 2012)
231
0
            QL_FAIL("MOEX calendar for the year " << y
232
0
                    << " does not exist.");
233
234
0
        if (isWorkingWeekend(d,m,y))
235
0
            return true;
236
237
        // Known holidays
238
0
        if (isWeekend(w)
239
            // Defender of the Fatherland Day
240
0
            || (d == 23 && m == February)
241
            // International Women's Day (possibly moved to Monday)
242
0
            || ((d == 8 || ((d == 9 || d == 10) && w == Monday)) && m == March)
243
            // Labour Day
244
0
            || (d == 1 && m == May)
245
            // Victory Day (possibly moved to Monday)
246
0
            || ((d == 9 || ((d == 10 || d == 11) && w == Monday)) && m == May)
247
            // Russia Day
248
0
            || (d == 12 && m == June)
249
            // Unity Day (possibly moved to Monday)
250
0
            || ((d == 4 || ((d == 5 || d == 6) && w == Monday))
251
0
                && m == November)
252
            // New Years Eve
253
0
            || (d == 31 && m == December))
254
0
            return false;
255
256
0
        if (isExtraHolidayExchangeImpl(d,m,y))
257
0
            return false;
258
259
0
        return true;
260
0
    }
261
262
}