Skip to content

Commit

Permalink
Add exchanges Dusseldorf & Hamburg; shift Frankfurt early close
Browse files Browse the repository at this point in the history
Add exchanges Dusseldorf & Hamburg. Their schedules appear identical,
but I'm basing off tradinghours.com because English resources not as good
as for Frankfurt.

Then I shifted Frankfurt's early close, because CBOE thinks its 2pm.
https://www.cboe.com/about/hours/european-equities
I couldn't find any other confirmation of what early close should be.
  • Loading branch information
ValueRaider committed Jun 1, 2024
1 parent 588ae13 commit c83a167
Show file tree
Hide file tree
Showing 10 changed files with 17,902 additions and 15 deletions.
4 changes: 4 additions & 0 deletions exchange_calendars/calendar_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
from .exchange_calendar_xcbf import XCBFExchangeCalendar
from .exchange_calendar_xcse import XCSEExchangeCalendar
from .exchange_calendar_xdub import XDUBExchangeCalendar
from .exchange_calendar_xdus import XDUSExchangeCalendar
from .exchange_calendar_xeee import XEEEExchangeCalendar
from .exchange_calendar_xetr import XETRExchangeCalendar
from .exchange_calendar_xfra import XFRAExchangeCalendar
from .exchange_calendar_xham import XHAMExchangeCalendar
from .exchange_calendar_xhel import XHELExchangeCalendar
from .exchange_calendar_xhkg import XHKGExchangeCalendar
from .exchange_calendar_xice import XICEExchangeCalendar
Expand Down Expand Up @@ -82,9 +84,11 @@
"XCBF": XCBFExchangeCalendar,
"XCSE": XCSEExchangeCalendar,
"XDUB": XDUBExchangeCalendar,
"XDUS": XDUSExchangeCalendar,
"XEEE": XEEEExchangeCalendar,
"XFRA": XFRAExchangeCalendar,
"XETR": XETRExchangeCalendar,
"XHAM": XHAMExchangeCalendar,
"XHEL": XHELExchangeCalendar,
"XHKG": XHKGExchangeCalendar,
"XICE": XICEExchangeCalendar,
Expand Down
138 changes: 138 additions & 0 deletions exchange_calendars/exchange_calendar_xdus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# LICENSE HERE

from datetime import time
from zoneinfo import ZoneInfo

from pandas import Timestamp
from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday, previous_workday

from .common_holidays import (
boxing_day,
christmas,
christmas_eve,
european_labour_day,
new_years_day,
new_years_eve,
whit_monday,
)
from .exchange_calendar import HolidayCalendar, ExchangeCalendar

# Regular Holidays
# ----------------
NewYearsDay = new_years_day()

EuropeanLabourDay = european_labour_day()

# Whit Monday observed in 2007, before it became regularly observed
# starting in 2015.
WhitMonday2007AdHoc = Timestamp("2007-05-28")

# Whit Monday and the Day of German Unity have been observed regularly, but in 2022 regular trading took place instead.
# It's unclear if it will be observed in 2023.
WhitMondayUntil2022 = whit_monday(start_date="2015-01-01", end_date="2022-01-01")

DayOfGermanUnityUntil2022 = Holiday(
"Day of German Unity",
month=10,
day=3,
start_date="2014-01-01",
end_date="2022-01-01",
)

# Reformation Day was a German national holiday in 2017.
ReformationDay500thAnniversaryAdHoc = Timestamp("2017-10-31")

ChristmasEve = christmas_eve()

Christmas = christmas()

BoxingDay = boxing_day()

NewYearsEve = new_years_eve()

# Early Closes
# ------------
# The last weekday before Dec 31 is an early close starting in 2010.
LastWorkingDay = Holiday(
"Last Working Day of Year Early Close",
month=12,
day=31,
start_date="2010-01-01",
observance=previous_workday,
)


class XDUSExchangeCalendar(ExchangeCalendar):
"""
Exchange calendar for the Dusseldorf Stock Exchange (XHAM).
Compared to Frankfurt:
- same holidays
- earlier open, later close
Identical to Hamburg
Open Time: 8:00 AM, CET
Close Time: 10:00 PM, CET
Regularly-Observed Holidays:
- New Years Day
- Good Friday
- Easter Monday
- Whit Monday
- Labour Day
- Day of German Unity
- Christmas Eve
- Christmas Day
- Boxing Day
Early Closes:
- Last working day before Dec. 31
"""

# TODO: verify the early close time
# Assume same as Frankfurt
regular_early_close = time(14)

name = "XDUS"

tz = ZoneInfo("CET")

open_times = ((None, time(8)),)

close_times = ((None, time(22)),)

@property
def regular_holidays(self):
return HolidayCalendar(
[
NewYearsDay,
GoodFriday,
EasterMonday,
EuropeanLabourDay,
WhitMondayUntil2022,
DayOfGermanUnityUntil2022,
ChristmasEve,
Christmas,
BoxingDay,
NewYearsEve,
]
)

@property
def adhoc_holidays(self):
return [
WhitMonday2007AdHoc,
ReformationDay500thAnniversaryAdHoc,
]

@property
def special_closes(self):
return [
(
self.regular_early_close,
HolidayCalendar(
[
LastWorkingDay,
]
),
)
]
7 changes: 6 additions & 1 deletion exchange_calendars/exchange_calendar_xfra.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,12 @@ class XFRAExchangeCalendar(ExchangeCalendar):
"""

# TODO: verify the early close time
regular_early_close = time(12, 30)
# regular_early_close = time(12, 30)
#
# Update: CBOE thinks 2pm
# https://www.cboe.com/about/hours/european-equities
# But still need official confirmation!
regular_early_close = time(14)

name = "XFRA"

Expand Down
138 changes: 138 additions & 0 deletions exchange_calendars/exchange_calendar_xham.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# LICENSE HERE

from datetime import time
from zoneinfo import ZoneInfo

from pandas import Timestamp
from pandas.tseries.holiday import EasterMonday, GoodFriday, Holiday, previous_workday

from .common_holidays import (
boxing_day,
christmas,
christmas_eve,
european_labour_day,
new_years_day,
new_years_eve,
whit_monday,
)
from .exchange_calendar import HolidayCalendar, ExchangeCalendar

# Regular Holidays
# ----------------
NewYearsDay = new_years_day()

EuropeanLabourDay = european_labour_day()

# Whit Monday observed in 2007, before it became regularly observed
# starting in 2015.
WhitMonday2007AdHoc = Timestamp("2007-05-28")

# Whit Monday and the Day of German Unity have been observed regularly, but in 2022 regular trading took place instead.
# It's unclear if it will be observed in 2023.
WhitMondayUntil2022 = whit_monday(start_date="2015-01-01", end_date="2022-01-01")

DayOfGermanUnityUntil2022 = Holiday(
"Day of German Unity",
month=10,
day=3,
start_date="2014-01-01",
end_date="2022-01-01",
)

# Reformation Day was a German national holiday in 2017.
ReformationDay500thAnniversaryAdHoc = Timestamp("2017-10-31")

ChristmasEve = christmas_eve()

Christmas = christmas()

BoxingDay = boxing_day()

NewYearsEve = new_years_eve()

# Early Closes
# ------------
# The last weekday before Dec 31 is an early close starting in 2010.
LastWorkingDay = Holiday(
"Last Working Day of Year Early Close",
month=12,
day=31,
start_date="2010-01-01",
observance=previous_workday,
)


class XHAMExchangeCalendar(ExchangeCalendar):
"""
Exchange calendar for the Hamburg Stock Exchange (XHAM).
Compared to Frankfurt:
- same holidays
- earlier open, later close
Identical to Dusseldorf
Open Time: 8:00 AM, CET
Close Time: 10:00 PM, CET
Regularly-Observed Holidays:
- New Years Day
- Good Friday
- Easter Monday
- Whit Monday
- Labour Day
- Day of German Unity
- Christmas Eve
- Christmas Day
- Boxing Day
Early Closes:
- Last working day before Dec. 31
"""

# TODO: verify the early close time
# Assume same as Frankfurt
regular_early_close = time(14)

name = "XHAM"

tz = ZoneInfo("CET")

open_times = ((None, time(8)),)

close_times = ((None, time(22)),)

@property
def regular_holidays(self):
return HolidayCalendar(
[
NewYearsDay,
GoodFriday,
EasterMonday,
EuropeanLabourDay,
WhitMondayUntil2022,
DayOfGermanUnityUntil2022,
ChristmasEve,
Christmas,
BoxingDay,
NewYearsEve,
]
)

@property
def adhoc_holidays(self):
return [
WhitMonday2007AdHoc,
ReformationDay500thAnniversaryAdHoc,
]

@property
def special_closes(self):
return [
(
self.regular_early_close,
HolidayCalendar(
[
LastWorkingDay,
]
),
)
]
Loading

0 comments on commit c83a167

Please sign in to comment.