Coverage for tests / test_datetools.py: 99%
504 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-27 14:36 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-27 14:36 +0000
1from unittest import main, TestCase
3import holidays
4from matplotlib.dates import relativedelta
5from rivapy.tools.datetools import calc_end_day, is_business_day, roll_day, Period, Schedule, DayCounter
6from rivapy.tools.enums import RollConvention, DayCounterType, RollRule
7import calendar
8from rivapy.tools.datetools import (
9 _date_to_datetime,
10 _is_ambiguous_date,
11 calc_end_day,
12 _is_IMM_date,
13 calc_start_day,
14 last_day_of_month,
15 is_last_day_of_month,
16 next_IMM_date,
17 last_business_day_of_month,
18 is_last_business_day_of_month,
19 nearest_business_day,
20 nearest_last_business_day_of_month,
21 next_or_previous_business_day,
22)
23from datetime import date, datetime
24from rivapy.tools.holidays_compat import DE, ECB
27class DayCounterTests(TestCase):
29 def test_yf(self):
30 d1 = datetime(2023, 1, 1)
31 d2 = datetime(2024, 1, 1)
32 self.assertAlmostEqual(DayCounter.yf_Act365Fixed(d1, d2), 1.0, delta=1e-5)
33 dc = DayCounter(DayCounterType.Act365Fixed)
34 self.assertAlmostEqual(DayCounter.yf_Act365Fixed(d1, d2), dc.yf(d1, d2), delta=1e-5)
36 d1 = datetime(2024, 12, 1)
37 d2 = datetime(2025, 2, 1)
38 self.assertAlmostEqual(DayCounter.yf_ActAct(d1, d2), 0.16963096040122763, delta=1e-5)
39 d1 = date(2024, 1, 1)
40 d2 = date(2025, 1, 1)
41 self.assertAlmostEqual(DayCounter.yf_Act360(d1, d2), 1.0166666666666666, delta=1e-5)
42 self.assertAlmostEqual(DayCounter.yf_Act365Fixed(d1, d2), 1.0027397260273974, delta=1e-5)
43 coupon_schedule = [date(2024, 5, 1), date(2024, 11, 1)]
44 self.assertEqual(DayCounter.yf_ActActICMA(date(2024, 5, 1), date(2024, 5, 31), coupon_schedule, coupon_frequency=2), 30 / 368)
46 self.assertAlmostEqual(DayCounter.yf_30360ISDA(date(2025, 1, 1), date(2025, 2, 1)), 0.08333333333333333, delta=1e-5)
47 self.assertAlmostEqual(DayCounter.yf_30360ISDA(date(2024, 12, 31), date(2025, 1, 31)), 0.08333333333333333, delta=1e-5)
48 self.assertAlmostEqual(DayCounter.yf_30360ISDA(date(2025, 4, 29), date(2025, 5, 30)), 0.08611111111111111, delta=1e-5)
49 self.assertAlmostEqual(DayCounter.yf_30360ISDA(date(2025, 4, 30), date(2025, 5, 31)), 0.08333333333333333, delta=1e-5)
51 self.assertAlmostEqual(DayCounter.yf_30E360(date(2024, 12, 31), date(2025, 1, 31)), 0.08333333333333333, delta=1e-5)
52 self.assertAlmostEqual(DayCounter.yf_30E360(date(2024, 12, 31), date(2025, 1, 30)), 0.08333333333333333, delta=1e-5)
53 self.assertAlmostEqual(DayCounter.yf_30E360(date(2024, 12, 30), date(2025, 1, 31)), 0.08333333333333333, delta=1e-5)
54 self.assertAlmostEqual(DayCounter.yf_30E360(date(2024, 12, 30), date(2025, 1, 30)), 0.08333333333333333, delta=1e-5)
56 self.assertAlmostEqual(DayCounter.yf_30U360(date(2024, 2, 29), date(2025, 2, 28)), 1.0, delta=1e-5)
57 self.assertAlmostEqual(DayCounter.yf_30U360(date(2024, 2, 28), date(2025, 2, 28)), 1.0, delta=1e-5)
58 self.assertAlmostEqual(DayCounter.yf_30U360(date(2023, 2, 28), date(2024, 2, 28)), 0.9944444444444445, delta=1e-5)
61class PeriodTests(TestCase):
63 def test_period(self):
64 p = Period(1975, 8, 22)
65 self.assertEqual(p.years, 1975)
66 self.assertEqual(p.months, 8)
67 self.assertEqual(p.days, 22)
68 self.assertTrue(p == Period(1975, 8, 22))
69 p = Period.from_string("T/N")
70 self.assertEqual(p.years, 0)
71 self.assertEqual(p.months, 0)
72 self.assertEqual(p.days, 1)
73 p = Period.from_string("O/N")
74 self.assertEqual(p.years, 0)
75 self.assertEqual(p.months, 0)
76 self.assertEqual(p.days, 1)
77 p = Period.from_string("5D")
78 self.assertEqual(p.years, 0)
79 self.assertEqual(p.months, 0)
80 self.assertEqual(p.days, 5)
81 P = Period.from_string("3M")
82 self.assertEqual(P.years, 0)
83 self.assertEqual(P.months, 3)
84 self.assertEqual(P.days, 0)
85 p = Period.from_string("2Y")
86 self.assertEqual(p.years, 2)
87 self.assertEqual(p.months, 0)
88 self.assertEqual(p.days, 0)
89 with self.assertRaises(Exception):
90 Period.from_string("1W")
93class OGandOwnTests(TestCase):
94 # These tests are shall reproduce the results given in [Chapter 4](https://usermanual.wiki/Document/interestrateinstrumentsandmarketconventionsguide.1425400940/view)
95 # of Interest Rate Instruments and Market Conventions Guide by OpenGamma
96 holidays_target2 = holidays.ECB(years=[2011, 2012])
97 holidays_de = holidays.DE(years=1997)
99 # OpenGamma Tests
100 def test_rolls(self):
101 start_date = date(2011, 8, 18)
102 end_date = start_date + relativedelta(months=1)
103 self.assertEqual(roll_day(end_date, self.holidays_target2, RollConvention.FOLLOWING), datetime(2011, 9, 19))
104 self.assertEqual(roll_day(end_date, self.holidays_target2, RollConvention.PRECEDING), datetime(2011, 9, 16))
105 start_date = date(2011, 6, 30)
106 end_date = start_date + relativedelta(months=1)
107 self.assertEqual(roll_day(end_date, self.holidays_target2, RollConvention.MODIFIED_FOLLOWING), datetime(2011, 7, 29))
108 self.assertEqual(roll_day(end_date, self.holidays_target2, RollConvention.FOLLOWING), datetime(2011, 8, 1))
109 self.assertEqual(roll_day(end_date, self.holidays_target2, RollConvention.MODIFIED_FOLLOWING), datetime(2011, 7, 29))
110 start_date = date(2011, 9, 15)
111 end_date = start_date + relativedelta(months=1)
112 self.assertEqual(roll_day(end_date, self.holidays_target2, RollConvention.MODIFIED_FOLLOWING_BIMONTHLY), datetime(2011, 10, 14))
113 self.assertEqual(roll_day(end_date, self.holidays_target2, RollConvention.FOLLOWING), datetime(2011, 10, 17))
114 start_date = date(2011, 2, 28)
115 end_date = start_date + relativedelta(months=1)
116 self.assertEqual(roll_day(end_date, self.holidays_target2, RollConvention.MODIFIED_FOLLOWING_EOM, start_date), datetime(2011, 3, 31))
117 start_date = date(2011, 4, 29)
118 end_date = start_date + relativedelta(months=1)
119 self.assertEqual(roll_day(end_date, self.holidays_target2, RollConvention.MODIFIED_FOLLOWING_EOM, start_date), datetime(2011, 5, 31))
120 start_date = date(2012, 2, 28)
121 end_date = start_date + relativedelta(months=1)
122 self.assertEqual(roll_day(end_date, self.holidays_target2, RollConvention.MODIFIED_FOLLOWING_EOM, start_date), datetime(2012, 3, 28))
124 # Own Tests
126 @staticmethod
127 def weekday(n):
128 name = {1: "Monday", 2: "Tuesday", 3: "Wednesday", 4: "Thursday", 5: "Friday", 6: "Saturday", 7: "Sunday"}
129 return name.get(n, "weekday(" + str(n) + ") is an invalid day of the week!")
131 def test_holidays(self):
132 for holiday_date, holiday_name in sorted(self.holidays_de.items()):
133 # self.assertTrue(
134 # self.weekday(holiday_date.isoweekday()) in [6, 7]
135 # or holiday_name
136 # in [
137 # "Neujahr",
138 # "Karfreitag",
139 # "Ostermontag",
140 # "Erster Mai",
141 # "Christi Himmelfahrt",
142 # "Pfingstmontag",
143 # "Tag der Deutschen Einheit",
144 # "Erster Weihnachtstag",
145 # "Zweiter Weihnachtstag",
146 # ],
147 # f"Unexpected holiday {holiday_name} on {holiday_date} ({self.weekday(holiday_date.isoweekday())})",
148 # )
149 self.assertTrue(
150 holiday_date
151 in [
152 date(1997, 1, 1),
153 date(1997, 3, 28),
154 date(1997, 3, 31),
155 date(1997, 5, 1),
156 date(1997, 5, 8),
157 date(1997, 5, 19),
158 date(1997, 10, 3),
159 date(1997, 12, 25),
160 date(1997, 12, 26),
161 ]
162 )
165class RollingSchedulingTests(TestCase):
166 def test_roll_day(self):
167 holidays_de = DE()
169 # business days are unchanged for all roll conventions
170 roll_conventions = [roll_convention.value for roll_convention in RollConvention]
171 roll_conventions.pop(2) # remove 'ModifiedFollowingEOM' as it needs a start date
172 for roll_convention in roll_conventions:
173 self.assertEqual(roll_day(date(1997, 1, 2), holidays_de, roll_convention), datetime(1997, 1, 2))
175 # test UNADJUSTED
176 roll_convention = RollConvention.UNADJUSTED
177 self.assertEqual(roll_day(datetime(1997, 5, 1), holidays_de, roll_convention), datetime(1997, 5, 1))
178 self.assertEqual(roll_day(datetime(1997, 7, 6), holidays_de, roll_convention), datetime(1997, 7, 6))
180 # test FOLLOWING
181 roll_convention = RollConvention.FOLLOWING
182 self.assertEqual(roll_day(datetime(1997, 5, 1), holidays_de, roll_convention), datetime(1997, 5, 2))
183 self.assertEqual(roll_day(datetime(1997, 7, 5), holidays_de, roll_convention), datetime(1997, 7, 7))
184 self.assertEqual(roll_day(datetime(1997, 5, 17), holidays_de, roll_convention), datetime(1997, 5, 20))
185 self.assertEqual(roll_day(datetime(1997, 12, 25), holidays_de, roll_convention), datetime(1997, 12, 29))
186 self.assertEqual(roll_day(datetime(1997, 3, 28), holidays_de, roll_convention), datetime(1997, 4, 1))
188 # test MODIFIED_FOLLOWING
189 roll_convention = RollConvention.MODIFIED_FOLLOWING
190 self.assertEqual(roll_day(datetime(1997, 5, 1), holidays_de, roll_convention), datetime(1997, 5, 2))
191 self.assertEqual(roll_day(datetime(1997, 12, 25), holidays_de, roll_convention), datetime(1997, 12, 29))
192 self.assertEqual(roll_day(datetime(1997, 8, 30), holidays_de, roll_convention), datetime(1997, 8, 29))
193 self.assertEqual(roll_day(datetime(1997, 8, 31), holidays_de, roll_convention), datetime(1997, 8, 29))
194 self.assertEqual(roll_day(datetime(1997, 3, 28), holidays_de, roll_convention), datetime(1997, 3, 27))
196 # test MODIFIED_FOLLOWING_BIMONTHLY
197 roll_convention = RollConvention.MODIFIED_FOLLOWING_BIMONTHLY
198 self.assertEqual(roll_day(datetime(1997, 5, 1), holidays_de, roll_convention), datetime(1997, 5, 2))
199 self.assertEqual(roll_day(datetime(1997, 12, 25), holidays_de, roll_convention), datetime(1997, 12, 29))
200 self.assertEqual(roll_day(datetime(1997, 8, 30), holidays_de, roll_convention), datetime(1997, 8, 29))
201 self.assertEqual(roll_day(datetime(1997, 8, 31), holidays_de, roll_convention), datetime(1997, 8, 29))
202 self.assertEqual(roll_day(datetime(1997, 3, 28), holidays_de, roll_convention), datetime(1997, 3, 27))
203 self.assertEqual(roll_day(datetime(1997, 2, 15), holidays_de, roll_convention), datetime(1997, 2, 14))
204 self.assertEqual(roll_day(datetime(1997, 2, 16), holidays_de, roll_convention), datetime(1997, 2, 17))
206 # test NEAREST
207 roll_convention = RollConvention.NEAREST
208 self.assertEqual(roll_day(datetime(1997, 5, 1), holidays_de, roll_convention), datetime(1997, 5, 2))
209 self.assertEqual(roll_day(datetime(1997, 7, 5), holidays_de, roll_convention), datetime(1997, 7, 4))
210 self.assertEqual(roll_day(datetime(1997, 7, 6), holidays_de, roll_convention), datetime(1997, 7, 7))
211 self.assertEqual(roll_day(datetime(1997, 5, 18), holidays_de, roll_convention), datetime(1997, 5, 20))
212 self.assertEqual(roll_day(datetime(1997, 3, 29), holidays_de, roll_convention), datetime(1997, 3, 27))
213 self.assertEqual(roll_day(datetime(1997, 3, 30), holidays_de, roll_convention), datetime(1997, 4, 1))
215 # test PRECEDING
216 roll_convention = RollConvention.PRECEDING
217 self.assertEqual(roll_day(datetime(1997, 5, 1), holidays_de, roll_convention), datetime(1997, 4, 30))
218 self.assertEqual(roll_day(datetime(1997, 7, 6), holidays_de, roll_convention), datetime(1997, 7, 4))
219 self.assertEqual(roll_day(datetime(1997, 5, 19), holidays_de, roll_convention), datetime(1997, 5, 16))
220 self.assertEqual(roll_day(datetime(1997, 12, 28), holidays_de, roll_convention), datetime(1997, 12, 24))
221 self.assertEqual(roll_day(datetime(1997, 3, 31), holidays_de, roll_convention), datetime(1997, 3, 27))
223 # test MODIFIED_PRECEDING
224 roll_convention = RollConvention.MODIFIED_PRECEDING
225 self.assertEqual(roll_day(datetime(1997, 5, 1), holidays_de, roll_convention), datetime(1997, 5, 2))
226 self.assertEqual(roll_day(datetime(1997, 7, 5), holidays_de, roll_convention), datetime(1997, 7, 4))
227 self.assertEqual(roll_day(datetime(1997, 7, 6), holidays_de, roll_convention), datetime(1997, 7, 4))
228 self.assertEqual(roll_day(datetime(1997, 3, 2), holidays_de, roll_convention), datetime(1997, 3, 3))
230 # test MODIFIED_FOLLOWING_EOM
231 roll_convention = RollConvention.MODIFIED_FOLLOWING_EOM
232 self.assertEqual(roll_day(datetime(1997, 3, 28), holidays_de, roll_convention, datetime(1997, 2, 28)), datetime(1997, 3, 27))
233 self.assertEqual(roll_day(datetime(1997, 4, 26), holidays_de, roll_convention, datetime(1997, 3, 26)), datetime(1997, 4, 28))
234 self.assertEqual(roll_day(datetime(1997, 4, 27), holidays_de, roll_convention, datetime(1997, 3, 27)), datetime(1997, 4, 30))
235 self.assertEqual(roll_day(datetime(1997, 6, 29), holidays_de, roll_convention, datetime(1997, 5, 29)), datetime(1997, 6, 30))
236 self.assertEqual(roll_day(datetime(1997, 7, 30), holidays_de, roll_convention, datetime(1997, 6, 30)), datetime(1997, 7, 31))
237 self.assertEqual(roll_day(datetime(1997, 8, 31), holidays_de, roll_convention, datetime(1997, 7, 31)), datetime(1997, 8, 29))
238 self.assertEqual(roll_day(datetime(1997, 9, 28), holidays_de, roll_convention, datetime(1997, 8, 28)), datetime(1997, 9, 29))
239 self.assertEqual(roll_day(datetime(1997, 9, 29), holidays_de, roll_convention, datetime(1997, 8, 29)), datetime(1997, 9, 30))
240 self.assertEqual(roll_day(datetime(1997, 11, 30), holidays_de, roll_convention, datetime(1997, 10, 30)), datetime(1997, 11, 28))
241 self.assertEqual(roll_day(datetime(1997, 12, 28), holidays_de, roll_convention, datetime(1997, 11, 28)), datetime(1997, 12, 31))
243 def test_schedule_generation(self):
244 holidays_de = ECB()
245 # test roll_out using differnt roll conventions
246 self.assertEqual(
247 Schedule._roll_out(datetime(2024, 1, 30), datetime(2024, 7, 31), Period(0, 1, 0), False, False, RollRule.NONE),
248 [
249 datetime(2024, 1, 30),
250 datetime(2024, 2, 29),
251 datetime(2024, 3, 29),
252 datetime(2024, 4, 29),
253 datetime(2024, 5, 29),
254 datetime(2024, 6, 29),
255 datetime(2024, 7, 29),
256 datetime(2024, 7, 31),
257 ],
258 ),
259 self.assertEqual(
260 Schedule._roll_out(datetime(2024, 1, 30), datetime(2024, 7, 31), Period(0, 1, 0), False, True, RollRule.NONE),
261 [
262 datetime(2024, 1, 30),
263 datetime(2024, 2, 29),
264 datetime(2024, 3, 29),
265 datetime(2024, 4, 29),
266 datetime(2024, 5, 29),
267 datetime(2024, 6, 29),
268 datetime(2024, 7, 31),
269 ],
270 ),
271 dates = Schedule._roll_out(datetime(2024, 7, 31), datetime(2024, 1, 30), Period(0, 1, 0), True, False, RollRule.NONE)
272 dates.reverse()
273 self.assertEqual(
274 dates,
275 [
276 datetime(2024, 7, 31),
277 datetime(2024, 6, 30),
278 datetime(2024, 5, 30),
279 datetime(2024, 4, 30),
280 datetime(2024, 3, 30),
281 datetime(2024, 2, 29),
282 datetime(2024, 1, 30),
283 ],
284 ),
285 dates = Schedule._roll_out(datetime(2024, 7, 31), datetime(2024, 1, 30), Period(0, 1, 0), True, True, RollRule.NONE)
286 dates.reverse()
287 self.assertEqual(
288 dates,
289 [
290 datetime(2024, 7, 31),
291 datetime(2024, 6, 30),
292 datetime(2024, 5, 30),
293 datetime(2024, 4, 30),
294 datetime(2024, 3, 30),
295 datetime(2024, 1, 30),
296 ],
297 ),
298 self.assertEqual(
299 Schedule._roll_out(datetime(2024, 1, 30), datetime(2024, 7, 31), Period(0, 1, 0), False, False, RollRule.EOM),
300 [
301 datetime(2024, 1, 31),
302 datetime(2024, 2, 29),
303 datetime(2024, 3, 31),
304 datetime(2024, 4, 30),
305 datetime(2024, 5, 31),
306 datetime(2024, 6, 30),
307 datetime(2024, 7, 31),
308 ],
309 ),
310 self.assertEqual(
311 Schedule._roll_out(datetime(2024, 1, 30), datetime(2024, 7, 31), Period(0, 1, 0), False, True, RollRule.EOM),
312 [
313 datetime(2024, 1, 31),
314 datetime(2024, 2, 29),
315 datetime(2024, 3, 31),
316 datetime(2024, 4, 30),
317 datetime(2024, 5, 31),
318 datetime(2024, 6, 30),
319 datetime(2024, 7, 31),
320 ],
321 ),
322 dates = Schedule._roll_out(datetime(2024, 7, 31), datetime(2024, 1, 30), Period(0, 1, 0), True, False, RollRule.EOM)
323 dates.reverse()
324 self.assertEqual(
325 dates,
326 [
327 datetime(2024, 7, 31),
328 datetime(2024, 6, 30),
329 datetime(2024, 5, 31),
330 datetime(2024, 4, 30),
331 datetime(2024, 3, 31),
332 datetime(2024, 2, 29),
333 datetime(2024, 1, 31),
334 ],
335 ),
336 dates = Schedule._roll_out(datetime(2024, 7, 31), datetime(2024, 1, 30), Period(0, 1, 0), True, True, RollRule.EOM)
337 dates.reverse()
338 self.assertEqual(
339 dates,
340 [
341 datetime(2024, 7, 31),
342 datetime(2024, 6, 30),
343 datetime(2024, 5, 31),
344 datetime(2024, 4, 30),
345 datetime(2024, 3, 31),
346 datetime(2024, 2, 29),
347 datetime(2024, 1, 31),
348 ],
349 ),
350 self.assertEqual(
351 Schedule._roll_out(datetime(2023, 11, 30), datetime(2024, 9, 30), Period(0, 3, 0), False, True, RollRule.EOM),
352 [
353 datetime(2023, 11, 30),
354 datetime(2024, 2, 29),
355 datetime(2024, 5, 31),
356 datetime(2024, 9, 30),
357 ],
358 ),
359 self.assertEqual(
360 Schedule._roll_out(datetime(2024, 1, 30), datetime(2024, 7, 31), Period(0, 1, 0), False, False, RollRule.DOM),
361 [
362 datetime(2024, 1, 30),
363 datetime(2024, 2, 29),
364 datetime(2024, 3, 30),
365 datetime(2024, 4, 30),
366 datetime(2024, 5, 30),
367 datetime(2024, 6, 30),
368 datetime(2024, 7, 30),
369 datetime(2024, 7, 31),
370 ],
371 ),
372 self.assertEqual(
373 Schedule._roll_out(datetime(2024, 1, 30), datetime(2024, 7, 31), Period(0, 1, 0), False, True, RollRule.DOM),
374 [
375 datetime(2024, 1, 30),
376 datetime(2024, 2, 29),
377 datetime(2024, 3, 30),
378 datetime(2024, 4, 30),
379 datetime(2024, 5, 30),
380 datetime(2024, 6, 30),
381 datetime(2024, 7, 31),
382 ],
383 ),
384 self.assertEqual(
385 Schedule._roll_out(datetime(2024, 1, 29), datetime(2024, 7, 31), Period(0, 1, 0), False, True, RollRule.DOM),
386 [
387 datetime(2024, 1, 29),
388 datetime(2024, 2, 29),
389 datetime(2024, 3, 29),
390 datetime(2024, 4, 29),
391 datetime(2024, 5, 29),
392 datetime(2024, 6, 29),
393 datetime(2024, 7, 31),
394 ],
395 ),
396 dates = Schedule._roll_out(datetime(2024, 7, 31), datetime(2024, 1, 30), Period(0, 1, 0), True, False, RollRule.DOM)
397 dates.reverse()
398 self.assertEqual(
399 dates,
400 [
401 datetime(2024, 7, 31),
402 datetime(2024, 6, 30),
403 datetime(2024, 5, 31),
404 datetime(2024, 4, 30),
405 datetime(2024, 3, 31),
406 datetime(2024, 2, 29),
407 datetime(2024, 1, 31),
408 datetime(2024, 1, 30),
409 ],
410 ),
411 dates = Schedule._roll_out(datetime(2024, 7, 31), datetime(2024, 1, 30), Period(0, 1, 0), True, True, RollRule.DOM)
412 dates.reverse()
413 self.assertEqual(
414 dates,
415 [
416 datetime(2024, 7, 31),
417 datetime(2024, 6, 30),
418 datetime(2024, 5, 31),
419 datetime(2024, 4, 30),
420 datetime(2024, 3, 31),
421 datetime(2024, 2, 29),
422 datetime(2024, 1, 30),
423 ],
424 ),
425 self.assertEqual(
426 Schedule._roll_out(datetime(2023, 12, 18), datetime(2024, 7, 31), Period(0, 3, 0), False, False, RollRule.IMM),
427 [
428 datetime(2023, 12, 20),
429 datetime(2024, 3, 20),
430 datetime(2024, 6, 19),
431 datetime(2024, 7, 31),
432 ],
433 ),
434 self.assertEqual(
435 Schedule._roll_out(datetime(2023, 12, 18), datetime(2024, 7, 31), Period(0, 3, 0), False, True, RollRule.IMM),
436 [
437 datetime(2023, 12, 20),
438 datetime(2024, 3, 20),
439 datetime(2024, 7, 31),
440 ],
441 ),
442 self.assertEqual(
443 Schedule._roll_out(datetime(2023, 12, 18), datetime(2024, 7, 31), Period(0, 1, 0), False, True, RollRule.IMM),
444 [
445 datetime(2023, 12, 20),
446 datetime(2024, 3, 20),
447 datetime(2024, 7, 31),
448 ],
449 ),
450 # self.assertEqual(
451 # Schedule._roll_out(datetime(2024, 7, 31), datetime(2023, 12, 18), Period(0, 3, 0), True, False, RollRule.IMM),
452 # [
453 # datetime(2024, 6, 19),
454 # datetime(2024, 3, 20),
455 # datetime(2023, 12, 20),
456 # datetime(2023, 12, 18),
457 # ],
458 # ),
459 # self.assertEqual(
460 # Schedule._roll_out(datetime(2024, 7, 31), datetime(2023, 12, 18), Period(0, 3, 0), True, True, RollRule.IMM),
461 # [
462 # datetime(2024, 6, 19),
463 # datetime(2024, 3, 20),
464 # datetime(2023, 12, 18),
465 # ],
466 # ),
467 self.assertEqual(
468 Schedule._roll_out(datetime(2023, 12, 21), datetime(2024, 2, 1), Period(0, 1, 0), False, True, RollRule.IMM),
469 [],
470 ),
471 # generate_dates with different periods and business day conventions
472 # sufficient to test with two different business day conventions? should be ok, if application of bdc is tested properly
473 self.assertEqual(
474 Schedule(
475 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 3, 0), True, True, RollConvention.UNADJUSTED, holidays_de
476 ).generate_dates(False),
477 [datetime(2020, 8, 21), datetime(2020, 11, 21), datetime(2021, 2, 21), datetime(2021, 5, 21), datetime(2021, 8, 21)],
478 )
479 self.assertEqual(
480 Schedule(
481 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 3, 0), True, False, RollConvention.UNADJUSTED, holidays_de
482 ).generate_dates(False),
483 [datetime(2020, 8, 21), datetime(2020, 11, 21), datetime(2021, 2, 21), datetime(2021, 5, 21), datetime(2021, 8, 21)],
484 )
485 self.assertEqual(
486 Schedule(
487 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 3, 0), False, True, RollConvention.UNADJUSTED, holidays_de
488 ).generate_dates(False),
489 [datetime(2020, 8, 21), datetime(2020, 11, 21), datetime(2021, 2, 21), datetime(2021, 5, 21), datetime(2021, 8, 21)],
490 )
491 self.assertEqual(
492 Schedule(
493 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 3, 0), False, False, RollConvention.UNADJUSTED, holidays_de
494 ).generate_dates(False),
495 [datetime(2020, 8, 21), datetime(2020, 11, 21), datetime(2021, 2, 21), datetime(2021, 5, 21), datetime(2021, 8, 21)],
496 )
498 self.assertEqual(
499 Schedule(
500 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 5, 0), True, True, RollConvention.UNADJUSTED, holidays_de
501 ).generate_dates(False),
502 [datetime(2020, 8, 21), datetime(2021, 3, 21), datetime(2021, 8, 21)],
503 )
504 self.assertEqual(
505 Schedule(
506 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 5, 0), True, False, RollConvention.UNADJUSTED, holidays_de
507 ).generate_dates(False),
508 [datetime(2020, 8, 21), datetime(2020, 10, 21), datetime(2021, 3, 21), datetime(2021, 8, 21)],
509 )
510 self.assertEqual(
511 Schedule(
512 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 5, 0), False, True, RollConvention.UNADJUSTED, holidays_de
513 ).generate_dates(False),
514 [datetime(2020, 8, 21), datetime(2021, 1, 21), datetime(2021, 8, 21)],
515 )
516 self.assertEqual(
517 Schedule(
518 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 5, 0), False, False, RollConvention.UNADJUSTED, holidays_de
519 ).generate_dates(False),
520 [datetime(2020, 8, 21), datetime(2021, 1, 21), datetime(2021, 6, 21), datetime(2021, 8, 21)],
521 )
523 self.assertEqual(
524 Schedule(
525 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 3, 0), True, True, RollConvention.MODIFIED_FOLLOWING, holidays_de
526 ).generate_dates(False),
527 [datetime(2020, 8, 21), datetime(2020, 11, 23), datetime(2021, 2, 22), datetime(2021, 5, 21), datetime(2021, 8, 23)],
528 )
529 self.assertEqual(
530 Schedule(
531 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 3, 0), True, False, RollConvention.MODIFIED_FOLLOWING, holidays_de
532 ).generate_dates(False),
533 [datetime(2020, 8, 21), datetime(2020, 11, 23), datetime(2021, 2, 22), datetime(2021, 5, 21), datetime(2021, 8, 23)],
534 )
535 self.assertEqual(
536 Schedule(
537 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 3, 0), False, True, RollConvention.MODIFIED_FOLLOWING, holidays_de
538 ).generate_dates(False),
539 [datetime(2020, 8, 21), datetime(2020, 11, 23), datetime(2021, 2, 22), datetime(2021, 5, 21), datetime(2021, 8, 23)],
540 )
541 self.assertEqual(
542 Schedule(
543 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 3, 0), False, False, RollConvention.MODIFIED_FOLLOWING, holidays_de
544 ).generate_dates(False),
545 [datetime(2020, 8, 21), datetime(2020, 11, 23), datetime(2021, 2, 22), datetime(2021, 5, 21), datetime(2021, 8, 23)],
546 )
548 self.assertEqual(
549 Schedule(
550 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 5, 0), True, True, RollConvention.MODIFIED_FOLLOWING, holidays_de
551 ).generate_dates(False),
552 [datetime(2020, 8, 21), datetime(2021, 3, 22), datetime(2021, 8, 23)],
553 )
554 self.assertEqual(
555 Schedule(
556 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 5, 0), True, False, RollConvention.MODIFIED_FOLLOWING, holidays_de
557 ).generate_dates(False),
558 [datetime(2020, 8, 21), datetime(2020, 10, 21), datetime(2021, 3, 22), datetime(2021, 8, 23)],
559 )
560 self.assertEqual(
561 Schedule(
562 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 5, 0), False, True, RollConvention.MODIFIED_FOLLOWING, holidays_de
563 ).generate_dates(False),
564 [datetime(2020, 8, 21), datetime(2021, 1, 21), datetime(2021, 8, 23)],
565 )
566 self.assertEqual(
567 Schedule(
568 datetime(2020, 8, 21), datetime(2021, 8, 21), Period(0, 5, 0), False, False, RollConvention.MODIFIED_FOLLOWING, holidays_de
569 ).generate_dates(False),
570 [datetime(2020, 8, 21), datetime(2021, 1, 21), datetime(2021, 6, 21), datetime(2021, 8, 23)],
571 )
573 def test_calc_end_day(self):
574 self.assertEqual(calc_end_day(datetime(2023, 1, 31), Period(0, 1, 0)), datetime(2023, 2, 28))
575 self.assertEqual(calc_end_day(datetime(2023, 1, 30), Period(0, 1, 0)), datetime(2023, 2, 28))
576 self.assertEqual(calc_end_day(datetime(2023, 1, 29), Period(0, 1, 0)), datetime(2023, 2, 28))
577 self.assertEqual(calc_end_day(datetime(2023, 1, 28), Period(0, 1, 0)), datetime(2023, 2, 28))
578 self.assertEqual(calc_end_day(datetime(2024, 1, 31), Period(0, 1, 0)), datetime(2024, 2, 29))
579 self.assertEqual(calc_end_day(datetime(2024, 1, 30), Period(0, 1, 0)), datetime(2024, 2, 29))
580 self.assertEqual(calc_end_day(datetime(2024, 1, 29), Period(0, 1, 0)), datetime(2024, 2, 29))
581 self.assertEqual(calc_end_day(datetime(2024, 1, 28), Period(0, 1, 0)), datetime(2024, 2, 28))
582 self.assertEqual(calc_end_day(datetime(2023, 2, 28), Period(0, 1, 0)), datetime(2023, 3, 28))
583 self.assertEqual(calc_end_day(datetime(2023, 2, 27), Period(0, 1, 0)), datetime(2023, 3, 27))
584 self.assertEqual(calc_end_day(datetime(2024, 2, 29), Period(0, 1, 0)), datetime(2024, 3, 29))
585 self.assertEqual(calc_end_day(datetime(2024, 2, 28), Period(0, 1, 0)), datetime(2024, 3, 28))
586 self.assertEqual(calc_end_day(datetime(2024, 2, 27), Period(0, 1, 0)), datetime(2024, 3, 27))
587 roll = RollRule(RollRule.EOM)
588 self.assertEqual(calc_end_day(datetime(2023, 1, 31), Period(0, 1, 0), roll_convention=roll), datetime(2023, 2, 28))
589 self.assertEqual(calc_end_day(datetime(2023, 1, 30), Period(0, 1, 0), roll_convention=roll), datetime(2023, 2, 28))
590 self.assertEqual(calc_end_day(datetime(2023, 1, 29), Period(0, 1, 0), roll_convention=roll), datetime(2023, 2, 28))
591 self.assertEqual(calc_end_day(datetime(2023, 1, 28), Period(0, 1, 0), roll_convention=roll), datetime(2023, 2, 28))
592 self.assertEqual(calc_end_day(datetime(2024, 1, 31), Period(0, 1, 0), roll_convention=roll), datetime(2024, 2, 29))
593 self.assertEqual(calc_end_day(datetime(2024, 1, 30), Period(0, 1, 0), roll_convention=roll), datetime(2024, 2, 29))
594 self.assertEqual(calc_end_day(datetime(2024, 1, 29), Period(0, 1, 0), roll_convention=roll), datetime(2024, 2, 29))
595 self.assertEqual(calc_end_day(datetime(2024, 1, 28), Period(0, 1, 0), roll_convention=roll), datetime(2024, 2, 28))
596 self.assertEqual(calc_end_day(datetime(2023, 2, 28), Period(0, 1, 0), roll_convention=roll), datetime(2023, 3, 31))
597 self.assertEqual(calc_end_day(datetime(2023, 2, 27), Period(0, 1, 0), roll_convention=roll), datetime(2023, 3, 27))
598 self.assertEqual(calc_end_day(datetime(2024, 2, 29), Period(0, 1, 0), roll_convention=roll), datetime(2024, 3, 31))
599 self.assertEqual(calc_end_day(datetime(2024, 2, 28), Period(0, 1, 0), roll_convention=roll), datetime(2024, 3, 31))
600 self.assertEqual(calc_end_day(datetime(2024, 2, 27), Period(0, 1, 0), roll_convention=roll), datetime(2024, 3, 27))
601 self.assertEqual(calc_end_day(datetime(2023, 3, 31), Period(0, 1, 0), roll_convention=roll), datetime(2023, 4, 30))
602 self.assertEqual(calc_end_day(datetime(2023, 3, 30), Period(0, 1, 0), roll_convention=roll), datetime(2023, 4, 30))
603 self.assertEqual(calc_end_day(datetime(2023, 3, 29), Period(0, 1, 0), roll_convention=roll), datetime(2023, 4, 29))
604 self.assertEqual(calc_end_day(datetime(2023, 3, 28), Period(0, 1, 0), roll_convention=roll), datetime(2023, 4, 28))
605 roll = RollRule(RollRule.DOM)
606 self.assertEqual(calc_end_day(datetime(2023, 1, 31), Period(0, 1, 0), roll_convention=roll), datetime(2023, 2, 28))
607 self.assertEqual(calc_end_day(datetime(2023, 1, 30), Period(0, 1, 0), roll_convention=roll), datetime(2023, 2, 28))
608 self.assertEqual(calc_end_day(datetime(2023, 1, 29), Period(0, 1, 0), roll_convention=roll), datetime(2023, 2, 28))
609 self.assertEqual(calc_end_day(datetime(2023, 1, 28), Period(0, 1, 0), roll_convention=roll), datetime(2023, 2, 28))
610 self.assertEqual(calc_end_day(datetime(2024, 1, 31), Period(0, 1, 0), roll_convention=roll), datetime(2024, 2, 29))
611 self.assertEqual(calc_end_day(datetime(2024, 1, 30), Period(0, 1, 0), roll_convention=roll), datetime(2024, 2, 29))
612 self.assertEqual(calc_end_day(datetime(2024, 1, 29), Period(0, 1, 0), roll_convention=roll), datetime(2024, 2, 29))
613 self.assertEqual(calc_end_day(datetime(2024, 1, 28), Period(0, 1, 0), roll_convention=roll), datetime(2024, 2, 28))
614 self.assertEqual(calc_end_day(datetime(2023, 2, 28), Period(0, 1, 0), roll_convention=roll), datetime(2023, 3, 28))
615 self.assertEqual(calc_end_day(datetime(2023, 2, 27), Period(0, 1, 0), roll_convention=roll), datetime(2023, 3, 27))
616 self.assertEqual(calc_end_day(datetime(2024, 2, 29), Period(0, 1, 0), roll_convention=roll), datetime(2024, 3, 29))
617 self.assertEqual(calc_end_day(datetime(2024, 2, 28), Period(0, 1, 0), roll_convention=roll), datetime(2024, 3, 28))
618 self.assertEqual(calc_end_day(datetime(2024, 2, 27), Period(0, 1, 0), roll_convention=roll), datetime(2024, 3, 27))
619 self.assertEqual(calc_end_day(datetime(2023, 3, 31), Period(0, 1, 0), roll_convention=roll), datetime(2023, 4, 30))
620 self.assertEqual(calc_end_day(datetime(2023, 3, 30), Period(0, 1, 0), roll_convention=roll), datetime(2023, 4, 30))
621 self.assertEqual(calc_end_day(datetime(2023, 3, 29), Period(0, 1, 0), roll_convention=roll), datetime(2023, 4, 29))
622 self.assertEqual(calc_end_day(datetime(2023, 3, 28), Period(0, 1, 0), roll_convention=roll), datetime(2023, 4, 28))
623 roll = RollRule(RollRule.IMM)
624 self.assertEqual(calc_end_day(datetime(2023, 1, 31), Period(0, 1, 0), roll_convention=roll), datetime(2023, 6, 21))
625 self.assertEqual(calc_end_day(datetime(2023, 2, 28), Period(0, 1, 0), roll_convention=roll), datetime(2023, 6, 21))
626 self.assertEqual(calc_end_day(datetime(2023, 3, 29), Period(0, 1, 0), roll_convention=roll), datetime(2023, 9, 20))
627 self.assertEqual(calc_end_day(datetime(2023, 1, 28), Period(0, 2, 0), roll_convention=roll), datetime(2023, 6, 21))
628 self.assertEqual(calc_end_day(datetime(2023, 1, 28), Period(0, 3, 0), roll_convention=roll), datetime(2023, 6, 21))
629 self.assertEqual(calc_end_day(datetime(2023, 3, 15), Period(0, 3, 0), roll_convention=roll), datetime(2023, 6, 21))
630 self.assertEqual(calc_end_day(datetime(2023, 3, 15), Period(0, 6, 0), roll_convention=roll), datetime(2023, 9, 20))
631 self.assertEqual(calc_end_day(datetime(2023, 1, 28), Period(0, 4, 0), roll_convention=roll), datetime(2023, 9, 20))
632 self.assertEqual(calc_end_day(datetime(2023, 3, 28), Period(0, 4, 0), roll_convention=roll), datetime(2023, 12, 20))
633 self.assertEqual(calc_end_day(datetime(2023, 3, 28), Period(0, 6, 0), roll_convention=roll), datetime(2023, 12, 20))
635 def test_is_ambiguous_date(self):
636 self.assertEqual(_is_ambiguous_date(datetime(2023, 1, 31)), False)
637 self.assertEqual(_is_ambiguous_date(datetime(2023, 2, 28)), True)
638 self.assertEqual(_is_ambiguous_date(datetime(2024, 1, 31)), False)
639 self.assertEqual(_is_ambiguous_date(datetime(2024, 2, 27)), False)
640 self.assertEqual(_is_ambiguous_date(datetime(2024, 1, 30)), True)
641 self.assertEqual(_is_ambiguous_date(datetime(2024, 2, 29)), True)
642 self.assertEqual(_is_ambiguous_date(datetime(2024, 3, 30)), True)
643 self.assertEqual(_is_ambiguous_date(datetime(2024, 3, 29)), False)
644 self.assertEqual(_is_ambiguous_date(datetime(2024, 3, 31)), False)
646 def test_is_IMM_date(self):
647 self.assertEqual(_is_IMM_date(datetime(2023, 1, 18)), False)
648 self.assertEqual(_is_IMM_date(datetime(2023, 1, 19)), False)
649 self.assertEqual(_is_IMM_date(datetime(2023, 1, 20)), False)
650 self.assertEqual(_is_IMM_date(datetime(2023, 1, 21)), False)
651 self.assertEqual(_is_IMM_date(datetime(2023, 2, 15)), False)
652 self.assertEqual(_is_IMM_date(datetime(2023, 2, 16)), False)
653 self.assertEqual(_is_IMM_date(datetime(2023, 2, 17)), False)
654 self.assertEqual(_is_IMM_date(datetime(2023, 2, 18)), False)
655 self.assertEqual(_is_IMM_date(datetime(2023, 3, 15)), True)
656 self.assertEqual(_is_IMM_date(datetime(2023, 3, 16)), False)
657 self.assertEqual(_is_IMM_date(datetime(2023, 3, 17)), False)
658 self.assertEqual(_is_IMM_date(datetime(2023, 3, 22)), False)
659 self.assertEqual(_is_IMM_date(datetime(2023, 4, 19)), False)
660 self.assertEqual(_is_IMM_date(datetime(2023, 4, 20)), False)
661 self.assertEqual(_is_IMM_date(datetime(2023, 4, 21)), False)
662 self.assertEqual(_is_IMM_date(datetime(2023, 5, 17)), False)
663 self.assertEqual(_is_IMM_date(datetime(2023, 5, 18)), False)
664 self.assertEqual(_is_IMM_date(datetime(2023, 5, 19)), False)
665 self.assertEqual(_is_IMM_date(datetime(2023, 6, 21)), True)
666 self.assertEqual(_is_IMM_date(datetime(2023, 6, 20)), False)
667 self.assertEqual(_is_IMM_date(datetime(2023, 6, 23)), False)
668 self.assertEqual(_is_IMM_date(datetime(2023, 7, 19)), False)
669 self.assertEqual(_is_IMM_date(datetime(2023, 7, 20)), False)
670 self.assertEqual(_is_IMM_date(datetime(2023, 7, 21)), False)
672 def test_calc_start_day(self):
673 self.assertEqual(calc_start_day(datetime(2023, 1, 31), Period(0, 1, 0)), datetime(2022, 12, 31))
674 self.assertEqual(calc_start_day(datetime(2023, 1, 30), Period(0, 1, 0)), datetime(2022, 12, 30))
675 self.assertEqual(calc_start_day(datetime(2023, 1, 29), Period(0, 1, 0)), datetime(2022, 12, 29))
676 self.assertEqual(calc_start_day(datetime(2023, 1, 28), Period(0, 1, 0)), datetime(2022, 12, 28))
677 self.assertEqual(calc_start_day(datetime(2023, 1, 27), Period(0, 1, 0)), datetime(2022, 12, 27))
678 self.assertEqual(calc_start_day(datetime(2023, 1, 26), Period(0, 1, 0)), datetime(2022, 12, 26))
679 self.assertEqual(calc_start_day(datetime(2023, 1, 1), Period(0, 0, 1)), datetime(2022, 12, 31))
680 self.assertEqual(calc_start_day(datetime(2023, 1, 2), Period(0, 0, 1)), datetime(2023, 1, 1))
681 bdc = RollConvention.MODIFIED_FOLLOWING
682 self.assertEqual(calc_start_day(datetime(2023, 1, 31), Period(0, 1, 0), bdc), datetime(2022, 12, 31))
683 self.assertEqual(calc_start_day(datetime(2023, 1, 30), Period(0, 1, 0), bdc), datetime(2022, 12, 30))
684 self.assertEqual(calc_start_day(datetime(2023, 1, 29), Period(0, 1, 0), bdc), None)
685 self.assertEqual(calc_start_day(datetime(2023, 1, 28), Period(0, 1, 0), bdc), None)
686 self.assertEqual(calc_start_day(datetime(2023, 1, 27), Period(0, 1, 0), bdc), datetime(2022, 12, 27))
687 self.assertEqual(calc_start_day(datetime(2023, 1, 26), Period(0, 1, 0), bdc), datetime(2022, 12, 26))
688 self.assertEqual(calc_start_day(datetime(2023, 1, 1), Period(0, 0, 1), bdc), None)
689 self.assertEqual(calc_start_day(datetime(2023, 1, 2), Period(0, 0, 1), bdc), datetime(2023, 1, 1))
690 bdc = RollConvention.FOLLOWING
691 self.assertEqual(calc_start_day(datetime(2023, 1, 31), Period(0, 1, 0), bdc), datetime(2022, 12, 31))
692 self.assertEqual(calc_start_day(datetime(2023, 1, 30), Period(0, 1, 0), bdc), datetime(2022, 12, 30))
693 self.assertEqual(calc_start_day(datetime(2023, 1, 29), Period(0, 1, 0), bdc), None)
694 self.assertEqual(calc_start_day(datetime(2023, 1, 28), Period(0, 1, 0), bdc), None)
695 self.assertEqual(calc_start_day(datetime(2023, 1, 27), Period(0, 1, 0), bdc), datetime(2022, 12, 27))
696 self.assertEqual(calc_start_day(datetime(2023, 1, 26), Period(0, 1, 0), bdc), datetime(2022, 12, 26))
697 self.assertEqual(calc_start_day(datetime(2023, 1, 1), Period(0, 0, 1), bdc), None)
698 self.assertEqual(calc_start_day(datetime(2023, 1, 2), Period(0, 0, 1), bdc), datetime(2022, 12, 30))
699 bdc = RollConvention.PRECEDING
700 self.assertEqual(calc_start_day(datetime(2023, 1, 31), Period(0, 1, 0), bdc), datetime(2022, 12, 31))
701 self.assertEqual(calc_start_day(datetime(2023, 1, 30), Period(0, 1, 0), bdc), datetime(2022, 12, 30))
702 self.assertEqual(calc_start_day(datetime(2023, 1, 29), Period(0, 1, 0), bdc), None)
703 self.assertEqual(calc_start_day(datetime(2023, 1, 28), Period(0, 1, 0), bdc), None)
704 self.assertEqual(calc_start_day(datetime(2023, 1, 27), Period(0, 1, 0), bdc), datetime(2022, 12, 27))
705 self.assertEqual(calc_start_day(datetime(2023, 1, 26), Period(0, 1, 0), bdc), datetime(2022, 12, 26))
706 self.assertEqual(calc_start_day(datetime(2023, 1, 1), Period(0, 0, 1), bdc), None)
707 self.assertEqual(calc_start_day(datetime(2023, 1, 2), Period(0, 0, 1), bdc), datetime(2023, 1, 1))
709 def test_last_day_of_month(self):
710 self.assertEqual(last_day_of_month(datetime(2023, 1, 15)), date(2023, 1, 31))
711 self.assertEqual(last_day_of_month(datetime(2023, 2, 15)), date(2023, 2, 28))
712 self.assertEqual(last_day_of_month(datetime(2023, 3, 15)), date(2023, 3, 31))
713 self.assertEqual(last_day_of_month(datetime(2023, 4, 15)), date(2023, 4, 30))
714 self.assertEqual(last_day_of_month(datetime(2023, 5, 15)), date(2023, 5, 31))
715 self.assertEqual(last_day_of_month(datetime(2023, 6, 15)), date(2023, 6, 30))
716 self.assertEqual(last_day_of_month(datetime(2023, 7, 15)), date(2023, 7, 31))
717 self.assertEqual(last_day_of_month(datetime(2023, 8, 15)), date(2023, 8, 31))
718 self.assertEqual(last_day_of_month(datetime(2023, 9, 15)), date(2023, 9, 30))
719 self.assertEqual(last_day_of_month(datetime(2023, 10, 15)), date(2023, 10, 31))
720 self.assertEqual(last_day_of_month(datetime(2023, 11, 15)), date(2023, 11, 30))
721 self.assertEqual(last_day_of_month(datetime(2023, 12, 15)), date(2023, 12, 31))
722 self.assertEqual(last_day_of_month(datetime(2024, 1, 15)), date(2024, 1, 31))
723 self.assertEqual(last_day_of_month(datetime(2024, 2, 15)), date(2024, 2, 29))
725 def test_is_last_day_of_month(self):
726 self.assertEqual(is_last_day_of_month(datetime(2023, 1, 31)), True)
727 self.assertEqual(is_last_day_of_month(datetime(2023, 2, 28)), True)
728 self.assertEqual(is_last_day_of_month(datetime(2024, 2, 28)), False)
729 self.assertEqual(is_last_day_of_month(datetime(2024, 2, 29)), True)
730 self.assertEqual(is_last_day_of_month(datetime(2023, 3, 31)), True)
731 self.assertEqual(is_last_day_of_month(datetime(2023, 4, 30)), True)
732 self.assertEqual(is_last_day_of_month(datetime(2023, 4, 29)), False)
734 def test_is_business_day(self):
735 holidays_de = ECB()
736 self.assertEqual(is_business_day(datetime(2023, 1, 2), holidays_de), True) # New Year's Day observed
737 self.assertEqual(is_business_day(datetime(2023, 1, 3), holidays_de), True)
738 self.assertEqual(is_business_day(datetime(2023, 1, 7), holidays_de), False)
739 self.assertEqual(is_business_day(datetime(2023, 1, 8), holidays_de), False) # Sunday
740 self.assertEqual(is_business_day(datetime(2023, 1, 9), holidays_de), True) # Monday after New Year's Day
741 self.assertEqual(is_business_day(datetime(2023, 4, 7), holidays_de), False) # Good Friday
742 self.assertEqual(is_business_day(datetime(2023, 4, 10), holidays_de), False) # Easter Monday
743 self.assertEqual(is_business_day(datetime(2023, 5, 1), holidays_de), False) # Labour Day
744 self.assertEqual(is_business_day(datetime(2023, 5, 18), holidays_de), True) # Ascension Day
745 self.assertEqual(is_business_day(datetime(2023, 5, 29), holidays_de), True) # Whit Monday
746 self.assertEqual(is_business_day(datetime(2023, 6, 8), holidays_de), True) # Corpus Christi
747 self.assertEqual(is_business_day(datetime(2023, 10, 3), holidays_de), True) # German Unity Day
748 self.assertEqual(is_business_day(datetime(2023, 12, 25), holidays_de), False) # Christmas Day
749 self.assertEqual(is_business_day(datetime(2023, 12, 26), holidays_de), False) # Second Day of Christmas
750 self.assertEqual(is_business_day(datetime(2023, 12, 27), holidays_de), True)
751 self.assertEqual(is_business_day(datetime(2025, 4, 18), holidays_de), False) # Good Friday
752 holidays_de = DE()
753 self.assertEqual(is_business_day(datetime(2023, 1, 2), holidays_de), True) # New Year's Day observed
754 self.assertEqual(is_business_day(datetime(2023, 1, 3), holidays_de), True)
755 self.assertEqual(is_business_day(datetime(2023, 1, 7), holidays_de), False)
756 self.assertEqual(is_business_day(datetime(2023, 1, 8), holidays_de), False) # Sunday
757 self.assertEqual(is_business_day(datetime(2023, 1, 9), holidays_de), True) # Monday after New Year's Day
758 self.assertEqual(is_business_day(datetime(2023, 4, 7), holidays_de), False) # Good Friday
759 self.assertEqual(is_business_day(datetime(2023, 4, 10), holidays_de), False) # Easter Monday
760 self.assertEqual(is_business_day(datetime(2023, 5, 1), holidays_de), False) # Labour Day
761 self.assertEqual(is_business_day(datetime(2023, 5, 18), holidays_de), False) # Ascension Day
762 self.assertEqual(is_business_day(datetime(2023, 5, 29), holidays_de), False) # Whit Monday
763 self.assertEqual(is_business_day(datetime(2023, 6, 8), holidays_de), True) # Corpus Christi
764 self.assertEqual(is_business_day(datetime(2023, 10, 3), holidays_de), False) # German Unity Day
765 self.assertEqual(is_business_day(datetime(2023, 12, 25), holidays_de), False) # Christmas Day
766 self.assertEqual(is_business_day(datetime(2023, 12, 26), holidays_de), False) # Second Day of Christmas
767 self.assertEqual(is_business_day(datetime(2023, 12, 27), holidays_de), True)
768 self.assertEqual(is_business_day(datetime(2025, 4, 18), holidays_de), False) # Good Friday
770 def test_last_business_day_of_month(self):
771 self.assertEqual(last_business_day_of_month(datetime(2023, 1, 15), ECB()), date(2023, 1, 31))
772 self.assertEqual(last_business_day_of_month(datetime(2023, 2, 15), ECB()), date(2023, 2, 28))
773 self.assertEqual(last_business_day_of_month(datetime(2023, 3, 15), ECB()), date(2023, 3, 31))
774 self.assertEqual(last_business_day_of_month(datetime(2023, 4, 15), ECB()), date(2023, 4, 28))
775 self.assertEqual(last_business_day_of_month(datetime(2023, 5, 15), ECB()), date(2023, 5, 31))
776 self.assertEqual(last_business_day_of_month(datetime(2023, 6, 15), ECB()), date(2023, 6, 30))
777 self.assertEqual(last_business_day_of_month(datetime(2023, 7, 15), ECB()), date(2023, 7, 31))
778 self.assertEqual(last_business_day_of_month(datetime(2023, 8, 15), ECB()), date(2023, 8, 31))
779 self.assertEqual(last_business_day_of_month(datetime(2023, 9, 15), ECB()), date(2023, 9, 29))
780 self.assertEqual(last_business_day_of_month(datetime(2023, 10, 15), ECB()), date(2023, 10, 31))
781 self.assertEqual(last_business_day_of_month(datetime(2023, 11, 15), ECB()), date(2023, 11, 30))
782 self.assertEqual(last_business_day_of_month(datetime(2023, 12, 15), ECB()), date(2023, 12, 29))
783 self.assertEqual(last_business_day_of_month(datetime(2024, 1, 15), ECB()), date(2024, 1, 31))
784 self.assertEqual(last_business_day_of_month(datetime(2024, 2, 15), ECB()), date(2024, 2, 29))
786 def test_is_last_business_day_of_month(self):
787 self.assertEqual(is_last_business_day_of_month(datetime(2023, 1, 31), ECB()), True)
788 self.assertEqual(is_last_business_day_of_month(datetime(2023, 2, 27), ECB()), False)
789 self.assertEqual(is_last_business_day_of_month(datetime(2023, 3, 31), ECB()), True)
790 self.assertEqual(is_last_business_day_of_month(datetime(2023, 4, 28), ECB()), True)
791 self.assertEqual(is_last_business_day_of_month(datetime(2023, 5, 31), ECB()), True)
792 self.assertEqual(is_last_business_day_of_month(datetime(2023, 6, 30), ECB()), True)
793 self.assertEqual(is_last_business_day_of_month(datetime(2023, 7, 31), ECB()), True)
794 self.assertEqual(is_last_business_day_of_month(datetime(2023, 8, 31), ECB()), True)
795 self.assertEqual(is_last_business_day_of_month(datetime(2023, 9, 29), ECB()), True)
796 self.assertEqual(is_last_business_day_of_month(datetime(2023, 10, 30), ECB()), False)
797 self.assertEqual(is_last_business_day_of_month(datetime(2023, 11, 30), ECB()), True)
798 self.assertEqual(is_last_business_day_of_month(datetime(2023, 12, 30), ECB()), False)
799 self.assertEqual(is_last_business_day_of_month(datetime(2024, 1, 31), ECB()), True)
800 self.assertEqual(is_last_business_day_of_month(datetime(2024, 2, 28), ECB()), False)
802 def test_nearest_business_day(self):
803 self.assertEqual(nearest_business_day(datetime(2023, 1, 1), ECB()), datetime(2023, 1, 2))
804 self.assertEqual(nearest_business_day(datetime(2023, 1, 2), ECB()), datetime(2023, 1, 2))
805 self.assertEqual(nearest_business_day(datetime(2023, 1, 3), ECB()), datetime(2023, 1, 3))
806 self.assertEqual(nearest_business_day(datetime(2023, 1, 7), ECB()), datetime(2023, 1, 6))
807 self.assertEqual(nearest_business_day(datetime(2023, 1, 8), ECB()), datetime(2023, 1, 9))
808 self.assertEqual(nearest_business_day(datetime(2023, 1, 9), ECB()), datetime(2023, 1, 9))
809 self.assertEqual(nearest_business_day(datetime(2023, 4, 7), ECB()), datetime(2023, 4, 6)) # Good Friday
810 self.assertEqual(nearest_business_day(datetime(2023, 4, 8), ECB()), datetime(2023, 4, 6)) # Saturday
811 self.assertEqual(nearest_business_day(datetime(2023, 4, 9), ECB()), datetime(2023, 4, 11)) # Easter Sunday
812 self.assertEqual(nearest_business_day(datetime(2023, 4, 10), ECB()), datetime(2023, 4, 11)) # Easter Monday
813 self.assertEqual(nearest_business_day(datetime(2023, 12, 23), ECB()), datetime(2023, 12, 22))
814 self.assertEqual(nearest_business_day(datetime(2023, 12, 24), ECB()), datetime(2023, 12, 22)) # Sunday
815 self.assertEqual(nearest_business_day(datetime(2023, 12, 25), ECB()), datetime(2023, 12, 27)) # Christmas Day
816 self.assertEqual(nearest_business_day(datetime(2023, 12, 26), ECB()), datetime(2023, 12, 27)) # Second Day of Christmas
817 self.assertEqual(nearest_business_day(datetime(2023, 12, 27), ECB()), datetime(2023, 12, 27))
818 self.assertEqual(nearest_business_day(datetime(2023, 12, 30), ECB()), datetime(2023, 12, 29))
819 self.assertEqual(nearest_business_day(datetime(2023, 12, 31), ECB()), datetime(2024, 1, 2)) # New Year's Day observed
821 def test_nearest_last_business_day_of_month(self):
822 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 1, 15), ECB()), datetime(2023, 1, 31))
823 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 1, 30), ECB()), datetime(2023, 1, 31))
824 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 1, 31), ECB()), datetime(2023, 1, 31))
825 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 2, 1), ECB()), datetime(2023, 1, 31))
826 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 2, 14), ECB()), datetime(2023, 2, 28))
827 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 2, 15), ECB()), datetime(2023, 2, 28))
828 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 2, 27), ECB()), datetime(2023, 2, 28))
829 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 2, 28), ECB()), datetime(2023, 2, 28))
830 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 3, 1), ECB()), datetime(2023, 2, 28))
831 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 3, 15), ECB()), datetime(2023, 2, 28))
832 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 3, 15), ECB(), False), datetime(2023, 2, 28))
833 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 3, 16), ECB()), datetime(2023, 3, 31))
834 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 3, 30), ECB()), datetime(2023, 3, 31))
835 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 3, 31), ECB()), datetime(2023, 3, 31))
836 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 4, 1), ECB()), datetime(2023, 3, 31))
837 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 4, 13), ECB()), datetime(2023, 3, 31))
838 self.assertEqual(nearest_last_business_day_of_month(datetime(2023, 4, 14), ECB()), datetime(2023, 4, 28))
840 def test_next_or_previous_business_day(self):
841 self.assertEqual(next_or_previous_business_day(datetime(2023, 1, 1), ECB(), True), datetime(2023, 1, 2))
842 self.assertEqual(next_or_previous_business_day(datetime(2023, 1, 2), ECB(), True), datetime(2023, 1, 2))
843 self.assertEqual(next_or_previous_business_day(datetime(2023, 1, 3), ECB(), True), datetime(2023, 1, 3))
844 self.assertEqual(next_or_previous_business_day(datetime(2023, 1, 7), ECB(), True), datetime(2023, 1, 9))
845 self.assertEqual(next_or_previous_business_day(datetime(2023, 1, 8), ECB(), True), datetime(2023, 1, 9))
846 self.assertEqual(next_or_previous_business_day(datetime(2023, 1, 7), ECB(), False), datetime(2023, 1, 6))
847 self.assertEqual(next_or_previous_business_day(datetime(2023, 1, 8), ECB(), False), datetime(2023, 1, 6))
848 self.assertEqual(next_or_previous_business_day(datetime(2023, 1, 9), ECB(), True), datetime(2023, 1, 9))
849 self.assertEqual(next_or_previous_business_day(datetime(2023, 4, 7), ECB(), True), datetime(2023, 4, 11)) # Good Friday
850 self.assertEqual(next_or_previous_business_day(datetime(2023, 4, 8), ECB(), True), datetime(2023, 4, 11)) # Saturday
851 self.assertEqual(next_or_previous_business_day(datetime(2023, 4, 9), ECB(), True), datetime(2023, 4, 11)) # Easter Sunday
852 self.assertEqual(next_or_previous_business_day(datetime(2023, 4, 10), ECB(), True), datetime(2023, 4, 11)) # Easter Monday
853 self.assertEqual(next_or_previous_business_day(datetime(2023, 4, 7), ECB(), False), datetime(2023, 4, 6)) # Good Friday
854 self.assertEqual(next_or_previous_business_day(datetime(2023, 4, 8), ECB(), False), datetime(2023, 4, 6)) # Saturday
855 self.assertEqual(next_or_previous_business_day(datetime(2023, 4, 9), ECB(), False), datetime(2023, 4, 6)) # Easter Sunday
856 self.assertEqual(next_or_previous_business_day(datetime(2023, 4, 10), ECB(), False), datetime(2023, 4, 6)) # Easter Monday
857 self.assertEqual(next_or_previous_business_day(datetime(2023, 12, 23), ECB(), True), datetime(2023, 12, 27))
858 self.assertEqual(next_or_previous_business_day(datetime(2023, 12, 24), ECB(), True), datetime(2023, 12, 27)) # Sunday
859 self.assertEqual(next_or_previous_business_day(datetime(2023, 12, 25), ECB(), True), datetime(2023, 12, 27)) # Christmas Day
860 self.assertEqual(next_or_previous_business_day(datetime(2023, 12, 26), ECB(), False), datetime(2023, 12, 22)) # Second Day of Christmas
862 def test_next_IMM_date(self):
863 self.assertEqual(next_IMM_date(datetime(2023, 1, 15)), date(2023, 3, 15))
864 self.assertEqual(next_IMM_date(datetime(2023, 1, 16)), date(2023, 3, 15))
865 self.assertEqual(next_IMM_date(datetime(2023, 1, 17)), date(2023, 3, 15))
866 self.assertEqual(next_IMM_date(datetime(2023, 1, 18)), date(2023, 3, 15))
867 self.assertEqual(next_IMM_date(datetime(2023, 1, 19)), date(2023, 3, 15))
868 self.assertEqual(next_IMM_date(datetime(2023, 1, 20)), date(2023, 3, 15))
869 self.assertEqual(next_IMM_date(datetime(2023, 1, 21)), date(2023, 3, 15))
870 self.assertEqual(next_IMM_date(datetime(2023, 2, 15)), date(2023, 3, 15))
871 self.assertEqual(next_IMM_date(datetime(2023, 2, 16)), date(2023, 3, 15))
872 self.assertEqual(next_IMM_date(datetime(2023, 2, 17)), date(2023, 3, 15))
873 self.assertEqual(next_IMM_date(datetime(2023, 2, 18)), date(2023, 3, 15))
874 self.assertEqual(next_IMM_date(datetime(2023, 2, 19)), date(2023, 3, 15))
875 self.assertEqual(next_IMM_date(datetime(2023, 2, 20)), date(2023, 3, 15))
876 self.assertEqual(next_IMM_date(datetime(2023, 2, 21)), date(2023, 3, 15))
877 self.assertEqual(next_IMM_date(datetime(2023, 3, 14)), date(2023, 3, 15))
878 self.assertEqual(next_IMM_date(datetime(2023, 3, 15)), date(2023, 6, 21))
879 self.assertEqual(next_IMM_date(datetime(2023, 3, 16)), date(2023, 6, 21))
880 self.assertEqual(next_IMM_date(datetime(2023, 12, 19)), date(2023, 12, 20))
881 self.assertEqual(next_IMM_date(datetime(2023, 12, 20)), date(2024, 3, 20))
884if __name__ == "__main__":
885 main()