Skip to content

Commit

Permalink
Migrate NYSE holidays to ObservedHolidayBase
Browse files Browse the repository at this point in the history
  • Loading branch information
KJhellico committed Nov 10, 2023
1 parent fa26505 commit faf64d8
Showing 1 changed file with 32 additions and 56 deletions.
88 changes: 32 additions & 56 deletions holidays/financial/ny_stock_exchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,14 @@
from datetime import date
from datetime import timedelta as td

from holidays.calendars.gregorian import (
JAN,
FEB,
MAR,
APR,
MAY,
JUN,
JUL,
AUG,
SEP,
OCT,
NOV,
DEC,
MON,
_get_nth_weekday_of_month,
)
from holidays.calendars.gregorian import JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
from holidays.groups import ChristianHolidays, InternationalHolidays, StaticHolidays
from holidays.holiday_base import HolidayBase
from holidays.observed_holiday_base import ObservedHolidayBase, SAT_TO_PREV_FRI, SUN_TO_NEXT_MON


class NewYorkStockExchange(HolidayBase, ChristianHolidays, InternationalHolidays, StaticHolidays):
class NewYorkStockExchange(
ObservedHolidayBase, ChristianHolidays, InternationalHolidays, StaticHolidays
):
"""
Official regulations:
- https://www.nyse.com/publicdocs/nyse/regulation/nyse/NYSE_Rules.pdf
Expand All @@ -43,53 +30,43 @@ class NewYorkStockExchange(HolidayBase, ChristianHolidays, InternationalHolidays
"""

market = "NYSE"
observed_label = "%s (Observed)"

def __init__(self, *args, **kwargs):
ChristianHolidays.__init__(self)
InternationalHolidays.__init__(self)
StaticHolidays.__init__(self, NewYorkStockExchangeStaticHolidays)
kwargs.setdefault("observed_rule", SAT_TO_PREV_FRI + SUN_TO_NEXT_MON)
super().__init__(*args, **kwargs)

def _add_observed_holiday(self, name: str, dt: date) -> None:
if self._is_saturday(dt):
dt += td(days=-1)
name = f"{name} (Observed)"
elif self._is_sunday(dt):
dt += td(days=+1)
name = f"{name} (Observed)"

self._add_holiday(name, dt)
def _add_observed_holiday(self, name, *args) -> None:
dt = date(self._year, *args)
is_obs, _ = self._add_observed(dt, name)
if not is_obs:
self._add_holiday(name, dt)

def _populate(self, year):
super()._populate(year)

# New Year Day.
jan_1 = date(year, JAN, 1)
if not self._is_saturday(jan_1):
self._add_observed_holiday("New Year's Day", jan_1)

# https://www.nyse.com/publicdocs/nyse/regulation/nyse/NYSE_Rules.pdf
# As per Rule 7.2.: check if next year's NYD falls on Saturday and
# needs to be observed on Friday (Dec 31 of previous year).
dec_31 = date(year, DEC, 31)
if self._is_friday(dec_31):
self._add_observed_holiday("New Year's Day", dec_31 + td(days=+1))
name = "New Year's Day"
self._add_observed_holiday("New Year's Day", JAN, 1)
self._add_observed(self._next_year_new_years_day, name)

# MLK, 3rd Monday of January.
if year >= 1998:
self._add_holiday_3rd_mon_of_jan("Martin Luther King Jr. Day")

# LINCOLN BIRTHDAY: observed 1896 - 1953 and 1968, Feb 12 (observed)
if 1896 <= year <= 1953 or year == 1968:
self._add_observed_holiday("Lincoln's Birthday", date(year, FEB, 12))
self._add_observed_holiday("Lincoln's Birthday", FEB, 12)

# WASHINGTON'S BIRTHDAY: Feb 22 (obs) until 1971, then 3rd Mon of Feb
self._add_observed_holiday(
"Washington's Birthday",
date(year, FEB, 22)
if year <= 1970
else _get_nth_weekday_of_month(3, MON, FEB, self._year),
)
name = "Washington's Birthday"
if year <= 1970:
self._add_observed_holiday(name, FEB, 22)
else:
self._add_holiday_3rd_mon_of_feb(name)

# GOOD FRIDAY - closed every year except 1898, 1906, and 1907
if year not in {1898, 1906, 1907}:
Expand All @@ -98,31 +75,30 @@ def _populate(self, year):
# MEM DAY (May 30) - closed every year since 1873
# last Mon in May since 1971
if year >= 1873:
self._add_observed_holiday(
"Memorial Day",
date(year, MAY, 30)
if year <= 1970
else _get_nth_weekday_of_month(-1, MON, MAY, self._year),
)
name = "Memorial Day"
if year <= 1970:
self._add_observed_holiday(name, MAY, 30)
else:
self._add_holiday_last_mon_of_may(name)

# FLAG DAY: June 14th 1916 - 1953
if 1916 <= year <= 1953:
self._add_observed_holiday("Flag Day", date(year, JUN, 14))
self._add_observed_holiday("Flag Day", JUN, 14)

# JUNETEENTH: since 2022
if year >= 2022:
self._add_observed_holiday("Juneteenth National Independence Day", date(year, JUN, 19))
self._add_observed_holiday("Juneteenth National Independence Day", JUN, 19)

# INDEPENDENCE DAY (July 4) - history suggests closed every year
self._add_observed_holiday("Independence Day", date(year, JUL, 4))
self._add_observed_holiday("Independence Day", JUL, 4)

# LABOR DAY - first mon in Sept, since 1887
if year >= 1887:
self._add_holiday_1st_mon_of_sep("Labor Day")

# COLUMBUS DAY/INDIGENOUS PPL DAY: Oct 12 - closed 1909-1953
if 1909 <= year <= 1953:
self._add_observed_holiday("Columbus Day", date(year, OCT, 12))
self._add_observed_holiday("Columbus Day", OCT, 12)

# ELECTION DAY: Tuesday after first Monday in November (2 U.S. Code §7)
# closed until 1969, then closed pres years 1972-80
Expand All @@ -131,13 +107,13 @@ def _populate(self, year):

# VETERAN'S DAY: Nov 11 - closed 1918, 1921, 1934-1953
if year in {1918, 1921} or 1934 <= year <= 1953:
self._add_observed_holiday("Veteran's Day", date(year, NOV, 11))
self._add_observed_holiday("Veteran's Day", NOV, 11)

# THXGIVING DAY: 4th Thurs in Nov - closed every year
self._add_holiday_4th_thu_of_nov("Thanksgiving Day")

# XMAS DAY: Dec 25th - every year
self._add_observed_holiday("Christmas Day", date(year, DEC, 25))
self._add_observed_holiday("Christmas Day", DEC, 25)

# Special holidays.
if year == 1914:
Expand Down

0 comments on commit faf64d8

Please sign in to comment.