diff --git a/openbb_terminal/miscellaneous/data_sources_default.json b/openbb_terminal/miscellaneous/data_sources_default.json
index 03b940412d1..ce503e9048b 100644
--- a/openbb_terminal/miscellaneous/data_sources_default.json
+++ b/openbb_terminal/miscellaneous/data_sources_default.json
@@ -12,7 +12,8 @@
"open": ["Bursa"],
"closed": ["Bursa"],
"all": ["Bursa"],
- "exchange": ["Bursa"]
+ "exchange": ["Bursa"],
+ "holidays":["PandasMarketCalendars"]
},
"options": {
"unu": ["FDScanner"],
diff --git a/openbb_terminal/miscellaneous/i18n/en.yml b/openbb_terminal/miscellaneous/i18n/en.yml
index 9e3d873f8c4..a1003975072 100644
--- a/openbb_terminal/miscellaneous/i18n/en.yml
+++ b/openbb_terminal/miscellaneous/i18n/en.yml
@@ -164,6 +164,7 @@ en:
stocks/th/closed: show closed markets
stocks/th/all: show all markets
stocks/th/exchange: show one exchange
+ stocks/th/holidays: show all dates on which there is a market holiday
stocks/disc/pipo: past IPOs dates
stocks/disc/fipo: future IPOs dates
stocks/disc/gainers: show latest top gainers
diff --git a/openbb_terminal/stocks/tradinghours/pandas_market_cal_model.py b/openbb_terminal/stocks/tradinghours/pandas_market_cal_model.py
new file mode 100644
index 00000000000..981e145ccf8
--- /dev/null
+++ b/openbb_terminal/stocks/tradinghours/pandas_market_cal_model.py
@@ -0,0 +1,58 @@
+import logging
+import pandas_market_calendars as mcal
+
+import pandas as pd
+from openbb_terminal.decorators import log_start_end
+
+logger = logging.getLogger(__name__)
+
+
+@log_start_end(log=logger)
+def get_all_holiday_exchange_short_names() -> pd.DataFrame:
+ """Get all holiday exchanges short names.
+
+ Returns
+ -------
+ pd.DataFrame
+ All available exchanges with holiday data (short names)
+ """
+ exchange_short_names = mcal.calendar_registry.get_calendar_names()
+
+ df = pd.DataFrame(exchange_short_names, columns=["short_name"])
+
+ return df
+
+
+@log_start_end(log=logger)
+def get_exchange_holidays(exchange_symbol: str, year: int) -> pd.DataFrame:
+
+ """Get all short name of each exchange that we hold holiday calendar for.
+
+ Parameters
+ ----------
+ symbol : str
+ Exchange symbol
+ year : int
+ Calendar year
+
+ Returns
+ -------
+ pd.DataFrame
+ All available exchanges with holiday data (short names)
+ """
+
+ cal = mcal.get_calendar(exchange_symbol)
+ holidays = pd.DataFrame(cal.holidays().holidays)
+
+ start_date = str(year) + "-01-01"
+ end_date = str(year) + "-12-31"
+ holidays.columns = ["Holiday Date"]
+
+ mask = (holidays["Holiday Date"] >= start_date) & (
+ holidays["Holiday Date"] <= end_date
+ )
+ exchange_holidays = holidays.loc[mask].copy()
+
+ exchange_holidays["Holiday Date"] = exchange_holidays["Holiday Date"].astype(str)
+
+ return exchange_holidays
diff --git a/openbb_terminal/stocks/tradinghours/pandas_market_cal_view.py b/openbb_terminal/stocks/tradinghours/pandas_market_cal_view.py
new file mode 100644
index 00000000000..9ad362a4403
--- /dev/null
+++ b/openbb_terminal/stocks/tradinghours/pandas_market_cal_view.py
@@ -0,0 +1,55 @@
+import logging
+import pandas as pd
+
+from openbb_terminal.decorators import log_start_end
+from openbb_terminal.stocks.tradinghours import pandas_market_cal_model
+from openbb_terminal.helper_funcs import print_rich_table
+from openbb_terminal.rich_config import console
+
+logger = logging.getLogger(__name__)
+
+
+@log_start_end(log=logger)
+def get_all_holiday_exchange_short_names() -> pd.DataFrame:
+ """Get all holiday exchanges short names.
+
+ Parameters
+ ----------
+
+ Returns
+ -------
+ pd.DataFrame
+ All available exchange with holiday data short names
+ """
+
+ return pandas_market_cal_model.get_all_holiday_exchange_short_names()
+
+
+@log_start_end(log=logger)
+def display_exchange_holidays(exchange_symbol: str, year: int):
+ """Display current exchange holiday calendar.
+
+ Parameters
+ ----------
+ symbol : str
+ Exchange symbol
+ year : int
+ Calendar year
+ """
+
+ exchange = pandas_market_cal_model.get_exchange_holidays(exchange_symbol, year)
+
+ if len(exchange) == 0 or exchange.empty:
+ console.print(
+ "[red]"
+ + "No exchange data loaded.\n"
+ + "Make sure you picked a valid exchange symbol and year."
+ + "[/red]\n"
+ )
+ return
+
+ print_rich_table(
+ exchange,
+ show_index=False,
+ title=f"[bold]{exchange_symbol}[/bold]",
+ )
diff --git a/openbb_terminal/stocks/tradinghours/tradinghours_controller.py b/openbb_terminal/stocks/tradinghours/tradinghours_controller.py
index a7ccc2a2328..973901d922b 100644
--- a/openbb_terminal/stocks/tradinghours/tradinghours_controller.py
+++ b/openbb_terminal/stocks/tradinghours/tradinghours_controller.py
@@ -6,7 +6,7 @@ import logging
import os
from typing import List
-
+from datetime import date
import pandas as pd
from openbb_terminal.custom_prompt_toolkit import NestedCompleter
@@ -25,16 +25,21 @@ from openbb_terminal.stocks.tradinghours.tradinghours_helper import (
get_exchanges_short_names,
get_fd_equities_list,
)
-
+from openbb_terminal.stocks.tradinghours.pandas_market_cal_view import (
+ get_all_holiday_exchange_short_names,
+ display_exchange_holidays,
+)
logger = logging.getLogger(__name__)
+# pylint: disable=R0902
+
class TradingHoursController(BaseController):
"""Trading Hours Controller class."""
- CHOICES_COMMANDS = ["symbol", "open", "closed", "all", "exchange"]
+ CHOICES_COMMANDS = ["symbol", "open", "closed", "all", "exchange", "holidays"]
PATH = "/stocks/th/"
FILE_PATH = os.path.join(os.path.dirname(__file__), "README.md")
CHOICES_GENERATION = True
@@ -50,6 +55,9 @@ class TradingHoursController(BaseController):
short_names = short_names_df["short_name"].values
all_short_names = list(short_names) + list(short_names_index)
self.all_exchange_short_names = sorted(list(all_short_names))
+ self.all_holiday_exchange_short_names = sorted(
+ list(get_all_holiday_exchange_short_names()["short_name"].values)
+ )
self.symbol = None
self.symbol_name = None
@@ -75,7 +83,6 @@ class TradingHoursController(BaseController):
if session and obbff.USE_PROMPT_TOOLKIT:
choices: dict = self.choices_default
-
self.completer = NestedCompleter.from_nested_dict(choices)
def print_help(self):
@@ -92,6 +99,7 @@ class TradingHoursController(BaseController):
mt.add_cmd("closed")
mt.add_cmd("all")
mt.add_cmd("exchange")
+ mt.add_cmd("holidays")
mt.add_raw("\n")
mt.add_cmd("symbol")
mt.add_raw("\n")
@@ -231,3 +239,56 @@ class TradingHoursController(BaseController):
ns_parser = self.parse_known_args_and_warn(parser, other_args)
if ns_parser:
bursa_view.display_all()
+
+ @log_start_end(log=logger)
+ def call_holidays(self, other_args: List[str]):
+ """Process 'holidays' command."""
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+ prog="exchange",
+ description="Select the exchange and year you want see holidays for",
+ )
+ parser.add_argument(
+ "-n",
+ "--name",
+ help="Exchange short name",
+ dest="exchange",
+ required=True,
+ type=str.upper,
+ choices=self.all_holiday_exchange_short_names,
+ metavar="LSE",
+ )
+
+ parser.add_argument(
+ "-y",
+ "--year",
+ help="Year",
+ nargs="?",
+ type=int,
+ const=date.today().year,
+ dest="year",
+ metavar="year",
+ )
+
+ if (
+ other_args
+ and "-n" not in other_args[0]
+ and "--name" not in other_args[0]
+ and "-h" not in other_args
+ ):
+ other_args.insert(0, "-n")
+ other_args.insert(2, "-y")
+
+ ns_parser = self.parse_known_args_and_warn(parser, other_args)
+ if ns_parser:
+ if ns_parser.exchange:
+ if ns_parser.year:
+ display_exchange_holidays(ns_parser.exchange, ns_parser.year)
+ else:
+ display_exchange_holidays(ns_parser.exchange, date.today().year)
+ else:
+ logger.error("Select the exchange and year you want holiday calendar for.")
+ console.print(
+ "[red]Select the exchange and year you want holiday calendar for.[/red]\n"
+ )
diff --git a/website/content/terminal/stocks/th/holidays/_index.md b/website/content/terminal/stocks/th/holidays/_index.md
new file mode 100644
index 00000000000..70b8cdef549
--- /dev/null
+++ b/website/content/terminal/stocks/th/holidays/_index.md
@@ -0,0 +1,3 @@
+usage: `holidays LSE 2022`
+
+Exchange holiday info
\ No newline at end of file
diff --git a/website/old_content/terminal/stocks/th/_index.md b/website/old_content/terminal/stocks/th/_index.md
index 8651677f0b1..cf1900b31a7 100644
--- a/website/old_content/terminal/stocks/th/_index.md
+++ b/website/old_content/terminal/stocks/th/_index.md
@@ -20,13 +20,14 @@ Choose from: closed,
all or
exchange.
+holidays.
Below, examples are given what these commands display, note that the tables are purposely cut off to keep the
introduction compact.
````
(๐ฆ) /stocks/th/ $ open
- Open markets
+ Open markets
โโโโโโโณโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโณโโโโโโโโโโโโโ
โ โ name โ short_name โ
โกโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฉ
@@ -49,7 +50,7 @@ introduction compact.
(๐ฆ) /stocks/th/ $ closed
- Closed markets
+ Closed markets
โโโโโโโณโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโณโโโโโโโโโโโโโ
โ โ name โ short_name โ
โกโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฉ
@@ -74,7 +75,7 @@ introduction compact.
(๐ฆ) /stocks/th/ $ all
- World markets
+ World markets
โโโโโโโณโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโณโโโโโโโโโโโโโณโโโโโโโโ
โ โ name โ short_name โ open โ
โกโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฉ
@@ -120,10 +121,10 @@ Market open: False
Selected symbol
Symbol: FB2.L
-Name: LEVERAGE SHARES PUBLIC LIMITED
+Name: LEVERAGE SHARES PUBLIC LIMITED
Market open: False
-(๐ฆ) /stocks/th/ $ exchange BO
+(๐ฆ) /stocks/th/ $ exchange BO
โโโโโโโโโโโโโโโโโโโโโโโโโณโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ BSE โ
โกโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฉ
@@ -151,8 +152,35 @@ Market open: False
โโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ timezone โ Asia/Kolkata โ
โโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
-โ flag โ ๐ฎ๐ณ
+โ flag โ ๐ฎ๐ณ
โโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ open โ False โ
โโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+
+
+(๐ฆ) /stocks/th/ $ holidays BATS 2024
+ BATS
+โโโโโโโโณโโโโโโโโโโโโโโโ
+โ โ Holiday Date โ
+โกโโโโโโโโโโโโโโโโโโโโโโฉ
+โ 1805 โ 2024-01-01 โ
+โโโโโโโโผโโโโโโโโโโโโโโโค
+โ 1806 โ 2024-01-15 โ
+โโโโโโโโผโโโโโโโโโโโโโโโค
+โ 1807 โ 2024-02-19 โ
+โโโโโโโโผโโโโโโโโโโโโโโโค
+โ 1808 โ 2024-03-29 โ
+โโโโโโโโผโโโโโโโโโโโโโโโค
+โ 1809 โ 2024-05-27 โ
+โโโโโโโโผโโโโโโโโโโโโโโโค
+โ 1810 โ 2024-07-04 โ
+โโโโโโโโผโโโโโโโโโโโโโโโค
+โ 1811 โ 2024-09-02 โ
+โโโโโโโโผโโโโโโโโโโโโโโโค
+โ 1812 โ 2024-11-28 โ
+โโโโโโโโผโโโโโโโโโโโโโโโค
+โ 1813 โ 2024-12-25 โ
+โโโโโโโโดโโโโโโโโโโโโโโโ
+
````