Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Douglas Franklin
Eden Juscelino
Edison Robles
Edward Betts
Eesh Saxena
Eldar Mustafayev
Emmanuel Arias
Eugenio Panadero Maciá
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1994,6 +1994,13 @@ code when available. The following financial markets are available:
<td></td>
</tr>
<tr>
<td>London Stock Exchange</td>
<td>XLON</td>
<td>London Stock Exchange (LSE) market holidays</td>
<td></td>
<td></td>
</tr>
<tr>
<td>NASDAQ</td>
<td>XNAS</td>
<td>National Association of Securities Dealers Automated Quotations (NASDAQ) holidays</td>
Expand Down
1 change: 1 addition & 0 deletions holidays/financial/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from holidays.financial.hong_kong_stock_exchange import HongKongStockExchange, XHKG, HKEX, SEHK
from holidays.financial.ice_futures_europe import IceFuturesEurope, ICEFuturesEurope, IFEU
from holidays.financial.japan_exchange import JapanExchange, XJPX, JPX, TSE, OSE
from holidays.financial.london_stock_exchange import LondonStockExchange, XLON, LSE
from holidays.financial.nasdaq import NASDAQ, XNAS
from holidays.financial.national_stock_exchange_of_india import (
NationalStockExchangeOfIndia,
Expand Down
129 changes: 129 additions & 0 deletions holidays/financial/london_stock_exchange.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# holidays
# --------
# A fast, efficient Python library for generating country, province and state
# specific sets of holidays on the fly. It aims to make determining whether a
# specific date is a holiday as fast and flexible as possible.
#
# Authors: Vacanza Team and individual contributors (see CONTRIBUTORS file)
# dr-prodigy <dr.prodigy.github@gmail.com> (c) 2017-2023
# ryanss <ryanssdev@icloud.com> (c) 2014-2017
# Website: https://github.com/vacanza/holidays
# License: MIT (see LICENSE file)

from holidays.calendars.gregorian import APR, MAY, JUN, SEP
from holidays.constants import HALF_DAY, PUBLIC
from holidays.groups import ChristianHolidays, InternationalHolidays, StaticHolidays
from holidays.observed_holiday_base import (
ObservedHolidayBase,
SAT_SUN_TO_NEXT_MON,
SAT_SUN_TO_NEXT_MON_TUE,
)


class LondonStockExchange(
ObservedHolidayBase, ChristianHolidays, InternationalHolidays, StaticHolidays
):
"""London Stock Exchange holidays.

The London Stock Exchange (LSE) is closed on weekends and on the bank
holidays observed in England and Wales, together with a small number of
one-off bank holidays (royal events).

On Christmas Eve and New Year's Eve the exchange runs a shortened trading
session (an early close), available under the ``HALF_DAY`` category.

References:
* <https://en.wikipedia.org/wiki/London_Stock_Exchange>
* <https://en.wikipedia.org/wiki/Bank_holiday>
* [LSE business days](https://www.londonstockexchange.com/equities-trading/business-days)
"""

market = "XLON"
observed_label = "%s (observed)"
start_year = 2000
Comment on lines +37 to +41

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eeshsaxena the LSE also observes early closures/half days (like Christmas Eve and New Year's Eve). Here is the reference link

​We will need to add half-day support to make this fully accurate. I've already done the research on this, so I am happy to help you implement this section if you'd like! Just let me know

supported_categories = (HALF_DAY, PUBLIC)

def __init__(self, *args, **kwargs):
ChristianHolidays.__init__(self)
InternationalHolidays.__init__(self)
StaticHolidays.__init__(self, LondonStockExchangeStaticHolidays)
kwargs.setdefault("observed_rule", SAT_SUN_TO_NEXT_MON)
super().__init__(*args, **kwargs)

def _populate_public_holidays(self):
# New Year's Day.
self._add_observed(self._add_new_years_day("New Year's Day"))

# Good Friday.
self._add_good_friday("Good Friday")

# Easter Monday.
self._add_easter_monday("Easter Monday")

# May Day.
if self._year == 2020:
# Moved to mark the 75th anniversary of VE Day.
self._add_holiday_may_8("May Day")
else:
self._add_holiday_1st_mon_of_may("May Day")

# Spring Bank Holiday.
# Moved on the years of a Jubilee bank holiday.
spring_bank_dates = {
2002: (JUN, 4),
2012: (JUN, 4),
2022: (JUN, 2),
}
name = "Spring Bank Holiday"
if dt := spring_bank_dates.get(self._year):
self._add_holiday(name, dt)
else:
self._add_holiday_last_mon_of_may(name)

# Late Summer Bank Holiday.
self._add_holiday_last_mon_of_aug("Late Summer Bank Holiday")

# Christmas Day.
self._add_observed(self._add_christmas_day("Christmas Day"), rule=SAT_SUN_TO_NEXT_MON_TUE)

# Boxing Day.
self._add_observed(self._add_christmas_day_two("Boxing Day"), rule=SAT_SUN_TO_NEXT_MON_TUE)

def _populate_half_day_holidays(self):
# On these days the exchange runs a shortened session and closes early
# (12:30). The label makes it clear to end users that trading is only
# partial rather than the day being a full market holiday.
early_close_label = "%s (early close)"

# Christmas Eve.
self._add_christmas_eve(self._format_holiday_name(early_close_label, "Christmas Eve"))

# New Year's Eve.
self._add_new_years_eve(self._format_holiday_name(early_close_label, "New Year's Eve"))


class XLON(LondonStockExchange):
pass


class LSE(LondonStockExchange):
pass


class LondonStockExchangeStaticHolidays:
"""Special one-off bank holidays observed by the London Stock Exchange.

References:
* <https://en.wikipedia.org/wiki/Bank_holiday#List_of_additional_one-off_bank_holidays>
"""

special_public_holidays = {
2002: (JUN, 3, "Golden Jubilee of Elizabeth II"),
2011: (APR, 29, "Wedding of William and Catherine"),
2012: (JUN, 5, "Diamond Jubilee of Elizabeth II"),
2022: (
(JUN, 3, "Platinum Jubilee of Elizabeth II"),
(SEP, 19, "State Funeral of Queen Elizabeth II"),
),
2023: (MAY, 8, "Coronation of Charles III"),
}
1 change: 1 addition & 0 deletions holidays/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@
"hong_kong_stock_exchange": ("HongKongStockExchange", "XHKG", "HKEX", "SEHK"),
"ice_futures_europe": ("IceFuturesEurope", "IFEU", "ICEFuturesEurope"),
"japan_exchange": ("JapanExchange", "XJPX", "JPX", "TSE", "OSE"),
"london_stock_exchange": ("LondonStockExchange", "XLON", "LSE"),
"nasdaq": ("NASDAQ", "XNAS"),
"national_stock_exchange_of_india": ("NationalStockExchangeOfIndia", "XNSE", "NSE"),
"ny_stock_exchange": ("NewYorkStockExchange", "XNYS", "NYSE"),
Expand Down
152 changes: 152 additions & 0 deletions tests/financial/test_london_stock_exchange.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# holidays
Comment thread
KJhellico marked this conversation as resolved.
# --------
# A fast, efficient Python library for generating country, province and state
# specific sets of holidays on the fly. It aims to make determining whether a
# specific date is a holiday as fast and flexible as possible.
#
# Authors: Vacanza Team and individual contributors (see CONTRIBUTORS file)
# dr-prodigy <dr.prodigy.github@gmail.com> (c) 2017-2023
# ryanss <ryanssdev@icloud.com> (c) 2014-2017
# Website: https://github.com/vacanza/holidays
# License: MIT (see LICENSE file)

from unittest import TestCase

from holidays.financial.london_stock_exchange import LondonStockExchange, XLON, LSE
from tests.common import CommonFinancialTests


class TestLondonStockExchange(CommonFinancialTests, TestCase):
@classmethod
def setUpClass(cls):
super().setUpClass(LondonStockExchange)

def test_market_aliases(self):
self.assertAliases(LondonStockExchange, XLON, LSE)

def test_no_holidays(self):
self.assertNoHolidays(LondonStockExchange(years=1999))

Comment on lines +28 to +33

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def test_market_aliases(self):
self.assertAliases(LondonStockExchange, XLON, LSE)
def test_no_holidays(self):
self.assertNoHolidays(LondonStockExchange(years=1999))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eeshsaxena, this remains relevant.

def test_2002(self):
Comment thread
KJhellico marked this conversation as resolved.
Outdated
self.assertHolidays(
LondonStockExchange(years=2002),
("2002-01-01", "New Year's Day"),
("2002-03-29", "Good Friday"),
("2002-04-01", "Easter Monday"),
("2002-05-06", "May Day"),
("2002-06-03", "Golden Jubilee of Elizabeth II"),
("2002-06-04", "Spring Bank Holiday"),
("2002-08-26", "Late Summer Bank Holiday"),
("2002-12-25", "Christmas Day"),
("2002-12-26", "Boxing Day"),
)

def test_2011(self):
self.assertHolidays(
LondonStockExchange(years=2011),
("2011-01-01", "New Year's Day"),
("2011-01-03", "New Year's Day (observed)"),
("2011-04-22", "Good Friday"),
("2011-04-25", "Easter Monday"),
("2011-04-29", "Wedding of William and Catherine"),
("2011-05-02", "May Day"),
("2011-05-30", "Spring Bank Holiday"),
("2011-08-29", "Late Summer Bank Holiday"),
("2011-12-25", "Christmas Day"),
("2011-12-26", "Boxing Day"),
("2011-12-27", "Christmas Day (observed)"),
)

def test_2020(self):
self.assertHolidays(
LondonStockExchange(years=2020),
("2020-01-01", "New Year's Day"),
("2020-04-10", "Good Friday"),
("2020-04-13", "Easter Monday"),
("2020-05-08", "May Day"),
("2020-05-25", "Spring Bank Holiday"),
("2020-08-31", "Late Summer Bank Holiday"),
("2020-12-25", "Christmas Day"),
("2020-12-26", "Boxing Day"),
("2020-12-28", "Boxing Day (observed)"),
)

def test_2021(self):
self.assertHolidays(
LondonStockExchange(years=2021),
("2021-01-01", "New Year's Day"),
("2021-04-02", "Good Friday"),
("2021-04-05", "Easter Monday"),
("2021-05-03", "May Day"),
("2021-05-31", "Spring Bank Holiday"),
("2021-08-30", "Late Summer Bank Holiday"),
("2021-12-25", "Christmas Day"),
("2021-12-26", "Boxing Day"),
("2021-12-27", "Christmas Day (observed)"),
("2021-12-28", "Boxing Day (observed)"),
)

def test_2022(self):
self.assertHolidays(
LondonStockExchange(years=2022),
("2022-01-01", "New Year's Day"),
("2022-01-03", "New Year's Day (observed)"),
("2022-04-15", "Good Friday"),
("2022-04-18", "Easter Monday"),
("2022-05-02", "May Day"),
("2022-06-02", "Spring Bank Holiday"),
("2022-06-03", "Platinum Jubilee of Elizabeth II"),
("2022-08-29", "Late Summer Bank Holiday"),
("2022-09-19", "State Funeral of Queen Elizabeth II"),
("2022-12-25", "Christmas Day"),
("2022-12-26", "Boxing Day"),
("2022-12-27", "Christmas Day (observed)"),
)

def test_2023(self):
self.assertHolidays(
LondonStockExchange(years=2023),
("2023-01-01", "New Year's Day"),
("2023-01-02", "New Year's Day (observed)"),
("2023-04-07", "Good Friday"),
("2023-04-10", "Easter Monday"),
("2023-05-01", "May Day"),
("2023-05-08", "Coronation of Charles III"),
("2023-05-29", "Spring Bank Holiday"),
("2023-08-28", "Late Summer Bank Holiday"),
("2023-12-25", "Christmas Day"),
("2023-12-26", "Boxing Day"),
)

def test_2024(self):
self.assertHolidays(
LondonStockExchange(years=2024),
("2024-01-01", "New Year's Day"),
("2024-03-29", "Good Friday"),
("2024-04-01", "Easter Monday"),
("2024-05-06", "May Day"),
("2024-05-27", "Spring Bank Holiday"),
("2024-08-26", "Late Summer Bank Holiday"),
("2024-12-25", "Christmas Day"),
("2024-12-26", "Boxing Day"),
)

def test_2025(self):
self.assertHolidays(
LondonStockExchange(years=2025),
("2025-01-01", "New Year's Day"),
("2025-04-18", "Good Friday"),
("2025-04-21", "Easter Monday"),
("2025-05-05", "May Day"),
("2025-05-26", "Spring Bank Holiday"),
("2025-08-25", "Late Summer Bank Holiday"),
("2025-12-25", "Christmas Day"),
("2025-12-26", "Boxing Day"),
)

def test_2024_half_day(self):
self.assertHalfDayHolidaysInYear(
2024,
("2024-12-24", "Christmas Eve (early close)"),
("2024-12-31", "New Year's Eve (early close)"),
)